Fix KeyFlag conversion

This commit is contained in:
MattHag 2024-11-05 22:01:36 +01:00 committed by Peter F. Patel-Schneider
parent 6903eeefcd
commit ad3916e1b8
4 changed files with 63 additions and 37 deletions

View File

@ -260,8 +260,8 @@ class ReprogrammableKey:
return NamedInt(self._cid, task) return NamedInt(self._cid, task)
@property @property
def flags(self) -> List[str]: def flags(self) -> KeyFlag:
return list(common.flag_names(KeyFlag, self._flags)) return KeyFlag(self._flags)
class ReprogrammableKeyV4(ReprogrammableKey): class ReprogrammableKeyV4(ReprogrammableKey):
@ -321,10 +321,10 @@ class ReprogrammableKeyV4(ReprogrammableKey):
return ret return ret
@property @property
def mapping_flags(self) -> List[str]: def mapping_flags(self) -> MappingFlag:
if self._mapping_flags is None: if self._mapping_flags is None:
self._getCidReporting() self._getCidReporting()
return list(common.flag_names(MappingFlag, self._mapping_flags)) return MappingFlag(self._mapping_flags)
def set_diverted(self, value: bool): def set_diverted(self, value: bool):
"""If set, the control is diverted temporarily and reports presses as HID++ events.""" """If set, the control is diverted temporarily and reports presses as HID++ events."""
@ -407,7 +407,7 @@ class ReprogrammableKeyV4(ReprogrammableKey):
bfield = 0 bfield = 0
for f, v in flags.items(): for f, v in flags.items():
key_flag = FLAG_TO_CAPABILITY[f].name.lower() key_flag = FLAG_TO_CAPABILITY[f]
if v and key_flag not in self.flags: if v and key_flag not in self.flags:
raise exceptions.FeatureNotSupported( raise exceptions.FeatureNotSupported(
msg=f'Tried to set mapping flag "{f}" on control "{self.key}" ' msg=f'Tried to set mapping flag "{f}" on control "{self.key}" '

View File

@ -38,6 +38,8 @@ from . import settings
from . import settings_validator from . import settings_validator
from . import special_keys from . import special_keys
from .hidpp10_constants import Registers from .hidpp10_constants import Registers
from .hidpp20 import KeyFlag
from .hidpp20 import MappingFlag
from .hidpp20_constants import GestureId from .hidpp20_constants import GestureId
from .hidpp20_constants import ParamId from .hidpp20_constants import ParamId
@ -898,7 +900,7 @@ class DivertKeys(settings.Settings):
def read(self, device, key): def read(self, device, key):
key_index = device.keys.index(key) key_index = device.keys.index(key)
key_struct = device.keys[key_index] key_struct = device.keys[key_index]
return b"\x00\x00\x01" if "diverted" in key_struct.mapping_flags else b"\x00\x00\x00" return b"\x00\x00\x01" if MappingFlag.DIVERTED in key_struct.mapping_flags else b"\x00\x00\x00"
def write(self, device, key, data_bytes): def write(self, device, key, data_bytes):
key_index = device.keys.index(key) key_index = device.keys.index(key)
@ -926,20 +928,20 @@ class DivertKeys(settings.Settings):
sliding = gestures = None sliding = gestures = None
choices = {} choices = {}
if device.keys: if device.keys:
for k in device.keys: for key in device.keys:
if "divertable" in k.flags and "virtual" not in k.flags: if KeyFlag.DIVERTABLE in key.flags and KeyFlag.VIRTUAL not in key.flags:
if "raw XY" in k.flags: if KeyFlag.RAW_XY in key.flags:
choices[k.key] = setting_class.choices_gesture choices[key.key] = setting_class.choices_gesture
if gestures is None: if gestures is None:
gestures = MouseGesturesXY(device, name="MouseGestures") gestures = MouseGesturesXY(device, name="MouseGestures")
if _F.ADJUSTABLE_DPI in device.features: if _F.ADJUSTABLE_DPI in device.features:
choices[k.key] = setting_class.choices_universe choices[key.key] = setting_class.choices_universe
if sliding is None: if sliding is None:
sliding = DpiSlidingXY( sliding = DpiSlidingXY(
device, name="DpiSliding", show_notification=desktop_notifications.show device, name="DpiSliding", show_notification=desktop_notifications.show
) )
else: else:
choices[k.key] = setting_class.choices_divert choices[key.key] = setting_class.choices_divert
if not choices: if not choices:
return None return None
validator = cls(choices, key_byte_count=2, byte_count=1, mask=0x01) validator = cls(choices, key_byte_count=2, byte_count=1, mask=0x01)
@ -1111,7 +1113,7 @@ class SpeedChange(settings.Setting):
def build(cls, setting_class, device): def build(cls, setting_class, device):
key_index = device.keys.index(special_keys.CONTROL.DPI_Change) key_index = device.keys.index(special_keys.CONTROL.DPI_Change)
key = device.keys[key_index] if key_index is not None else None key = device.keys[key_index] if key_index is not None else None
if key is not None and "divertable" in key.flags: if key is not None and KeyFlag.DIVERTABLE in key.flags:
keys = [setting_class.choices_extra, key.key] keys = [setting_class.choices_extra, key.key]
return cls(choices=common.NamedInts.list(keys), byte_count=2) return cls(choices=common.NamedInts.list(keys), byte_count=2)

View File

@ -277,7 +277,6 @@ def _print_device(dev, num=None):
print(" %2d: %-26s, default: %-27s => %-26s" % (k.index, k.key, k.default_task, k.mapped_to)) print(" %2d: %-26s, default: %-27s => %-26s" % (k.index, k.key, k.default_task, k.mapped_to))
gmask_fmt = ",".join(k.group_mask) gmask_fmt = ",".join(k.group_mask)
gmask_fmt = gmask_fmt if gmask_fmt else "empty" gmask_fmt = gmask_fmt if gmask_fmt else "empty"
print(f" {', '.join(k.flags)}, pos:{int(k.pos)}, group:{int(k.group):1}, group mask:{gmask_fmt}")
flag_names = list(common.flag_names(hidpp20.KeyFlag, k.flags.value)) flag_names = list(common.flag_names(hidpp20.KeyFlag, k.flags.value))
print( print(
f" {', '.join(flag_names)}, pos:{int(k.pos)}, group:{int(k.group):1}, group mask:{gmask_fmt}" f" {', '.join(flag_names)}, pos:{int(k.pos)}, group:{int(k.group):1}, group mask:{gmask_fmt}"

View File

@ -22,6 +22,7 @@ from logitech_receiver import exceptions
from logitech_receiver import hidpp20 from logitech_receiver import hidpp20
from logitech_receiver import hidpp20_constants from logitech_receiver import hidpp20_constants
from logitech_receiver import special_keys from logitech_receiver import special_keys
from logitech_receiver.hidpp20 import KeyFlag
from logitech_receiver.hidpp20_constants import GestureId from logitech_receiver.hidpp20_constants import GestureId
from . import fake_hidpp from . import fake_hidpp
@ -154,13 +155,13 @@ def test_FeaturesArray_getitem(device, expected0, expected1, expected2, expected
@pytest.mark.parametrize( @pytest.mark.parametrize(
"device, index, cid, task_id, flags, default_task, flag_names", "device, index, cid, task_id, flags, default_task, expected_flags",
[ [
(device_standard, 2, 1, 1, 0x30, "Volume Up", ["reprogrammable", "divertable"]), (device_standard, 2, 1, 1, 0x30, "Volume Up", KeyFlag.REPROGRAMMABLE | KeyFlag.DIVERTABLE),
(device_standard, 1, 2, 2, 0x20, "Volume Down", ["divertable"]), (device_standard, 1, 2, 2, 0x20, "Volume Down", KeyFlag.DIVERTABLE),
], ],
) )
def test_reprogrammable_key_key(device, index, cid, task_id, flags, default_task, flag_names): def test_reprogrammable_key_key(device, index, cid, task_id, flags, default_task, expected_flags):
key = hidpp20.ReprogrammableKey(device, index, cid, task_id, flags) key = hidpp20.ReprogrammableKey(device, index, cid, task_id, flags)
assert key._device == device assert key._device == device
@ -170,14 +171,38 @@ def test_reprogrammable_key_key(device, index, cid, task_id, flags, default_task
assert key._flags == flags assert key._flags == flags
assert key.key == special_keys.CONTROL[cid] assert key.key == special_keys.CONTROL[cid]
assert key.default_task == common.NamedInt(cid, default_task) assert key.default_task == common.NamedInt(cid, default_task)
assert sorted(list(key.flags)) == sorted(flag_names) assert key.flags == expected_flags
@pytest.mark.parametrize( @pytest.mark.parametrize(
"device, index, cid, task_id, flags, pos, group, gmask, default_task, flag_names, group_names", "device, index, cid, task_id, flags, pos, group, gmask, default_task, expected_flags, group_names",
[ [
(device_standard, 1, 0x51, 0x39, 0x60, 0, 1, 1, "Right Click", ["divertable", "persistently divertable"], ["g1"]), (
(device_standard, 2, 0x52, 0x3A, 0x11, 1, 2, 3, "Mouse Middle Button", ["mse", "reprogrammable"], ["g1", "g2"]), device_standard,
1,
0x51,
0x39,
0x60,
0,
1,
1,
"Right Click",
KeyFlag.DIVERTABLE | KeyFlag.PERSISTENTLY_DIVERTABLE,
["g1"],
),
(
device_standard,
2,
0x52,
0x3A,
0x11,
1,
2,
3,
"Mouse Middle Button",
KeyFlag.MSE | KeyFlag.REPROGRAMMABLE,
["g1", "g2"],
),
( (
device_standard, device_standard,
3, 3,
@ -188,13 +213,13 @@ def test_reprogrammable_key_key(device, index, cid, task_id, flags, default_task
2, 2,
7, 7,
"Mouse Back Button", "Mouse Back Button",
["reprogrammable", "raw_xy"], KeyFlag.REPROGRAMMABLE | KeyFlag.RAW_XY,
["g1", "g2", "g3"], ["g1", "g2", "g3"],
), ),
], ],
) )
def test_reprogrammable_key_v4_key( def test_reprogrammable_key_v4_key(
device, index, cid, task_id, flags, pos, group, gmask, default_task, flag_names, group_names device, index, cid, task_id, flags, pos, group, gmask, default_task, expected_flags, group_names
): ):
key = hidpp20.ReprogrammableKeyV4(device, index, cid, task_id, flags, pos, group, gmask) key = hidpp20.ReprogrammableKeyV4(device, index, cid, task_id, flags, pos, group, gmask)
@ -208,21 +233,21 @@ def test_reprogrammable_key_v4_key(
assert key._gmask == gmask assert key._gmask == gmask
assert key.key == special_keys.CONTROL[cid] assert key.key == special_keys.CONTROL[cid]
assert key.default_task == common.NamedInt(cid, default_task) assert key.default_task == common.NamedInt(cid, default_task)
assert sorted(list(key.flags)) == sorted(flag_names) assert key.flags == expected_flags
assert list(key.group_mask) == group_names assert list(key.group_mask) == group_names
@pytest.mark.parametrize( @pytest.mark.parametrize(
"responses, index, mapped_to, remappable_to, mapping_flags", "responses, index, mapped_to, remappable_to, expected_mapping_flags",
[ [
(fake_hidpp.responses_key, 1, "Right Click", common.UnsortedNamedInts(Right_Click=81, Left_Click=80), []), (fake_hidpp.responses_key, 1, "Right Click", common.UnsortedNamedInts(Right_Click=81, Left_Click=80), MappingFlag(0)),
(fake_hidpp.responses_key, 2, "Left Click", None, ["diverted"]), (fake_hidpp.responses_key, 2, "Left Click", None, MappingFlag.DIVERTED),
(fake_hidpp.responses_key, 3, "Mouse Back Button", None, ["diverted", "persistently diverted"]), (fake_hidpp.responses_key, 3, "Mouse Back Button", None, MappingFlag.DIVERTED | MappingFlag.PERSISTENTLY_DIVERTED),
(fake_hidpp.responses_key, 4, "Mouse Forward Button", None, ["diverted", "raw XY diverted"]), (fake_hidpp.responses_key, 4, "Mouse Forward Button", None, MappingFlag.DIVERTED | MappingFlag.RAW_XY_DIVERTED),
], ],
) )
# these fields need access all the key data, so start by setting up a device and its key data # these fields need access all the key data, so start by setting up a device and its key data
def test_reprogrammable_key_v4_query(responses, index, mapped_to, remappable_to, mapping_flags): def test_reprogrammable_key_v4_query(responses, index, mapped_to, remappable_to, expected_mapping_flags):
device = fake_hidpp.Device( device = fake_hidpp.Device(
"KEY", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5 "KEY", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5
) )
@ -232,7 +257,7 @@ def test_reprogrammable_key_v4_query(responses, index, mapped_to, remappable_to,
assert key.mapped_to == mapped_to assert key.mapped_to == mapped_to
assert (key.remappable_to == remappable_to) or remappable_to is None assert (key.remappable_to == remappable_to) or remappable_to is None
assert list(key.mapping_flags) == mapping_flags assert key.mapping_flags == expected_mapping_flags
@pytest.mark.parametrize( @pytest.mark.parametrize(
@ -244,7 +269,7 @@ def test_reprogrammable_key_v4_query(responses, index, mapped_to, remappable_to,
(fake_hidpp.responses_key, 4, False, False, False, 0x50, ["0056020000", "0056080000", "0056200000", "0056000050"]), (fake_hidpp.responses_key, 4, False, False, False, 0x50, ["0056020000", "0056080000", "0056200000", "0056000050"]),
], ],
) )
def test_ReprogrammableKeyV4_set(responses, index, diverted, persistently_diverted, rawXY_reporting, remap, sets, mocker): def test_reprogrammable_key_v4_set(responses, index, diverted, persistently_diverted, rawXY_reporting, remap, sets, mocker):
responses += [fake_hidpp.Response(r, 0x530, r) for r in sets] responses += [fake_hidpp.Response(r, 0x530, r) for r in sets]
device = fake_hidpp.Device( device = fake_hidpp.Device(
"KEY", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5 "KEY", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5
@ -254,21 +279,21 @@ def test_ReprogrammableKeyV4_set(responses, index, diverted, persistently_divert
spy_request = mocker.spy(device, "request") spy_request = mocker.spy(device, "request")
key = device.keys[index] key = device.keys[index]
_mapping_flags = list(key.mapping_flags) _mapping_flags = key.mapping_flags
if hidpp20.KeyFlag.DIVERTABLE in key.flags or not diverted: if hidpp20.KeyFlag.DIVERTABLE in key.flags or not diverted:
key.set_diverted(diverted) key.set_diverted(diverted)
else: else:
with pytest.raises(exceptions.FeatureNotSupported): with pytest.raises(exceptions.FeatureNotSupported):
key.set_diverted(diverted) key.set_diverted(diverted)
assert ("diverted" in list(key.mapping_flags)) == (diverted and hidpp20.KeyFlag.DIVERTABLE in key.flags) assert (MappingFlag.DIVERTED in key.mapping_flags) == (diverted and hidpp20.KeyFlag.DIVERTABLE in key.flags)
if hidpp20.KeyFlag.PERSISTENTLY_DIVERTABLE in key.flags or not persistently_diverted: if hidpp20.KeyFlag.PERSISTENTLY_DIVERTABLE in key.flags or not persistently_diverted:
key.set_persistently_diverted(persistently_diverted) key.set_persistently_diverted(persistently_diverted)
else: else:
with pytest.raises(exceptions.FeatureNotSupported): with pytest.raises(exceptions.FeatureNotSupported):
key.set_persistently_diverted(persistently_diverted) key.set_persistently_diverted(persistently_diverted)
assert (hidpp20.KeyFlag.PERSISTENTLY_DIVERTABLE in key.mapping_flags) == ( assert (hidpp20.MappingFlag.PERSISTENTLY_DIVERTED in key.mapping_flags) == (
persistently_diverted and hidpp20.KeyFlag.PERSISTENTLY_DIVERTABLE in key.flags persistently_diverted and hidpp20.KeyFlag.PERSISTENTLY_DIVERTABLE in key.flags
) )
@ -277,7 +302,7 @@ def test_ReprogrammableKeyV4_set(responses, index, diverted, persistently_divert
else: else:
with pytest.raises(exceptions.FeatureNotSupported): with pytest.raises(exceptions.FeatureNotSupported):
key.set_rawXY_reporting(rawXY_reporting) key.set_rawXY_reporting(rawXY_reporting)
assert ("raw XY diverted" in list(key.mapping_flags)) == (rawXY_reporting and hidpp20.KeyFlag.RAW_XY in key.flags) assert (MappingFlag.RAW_XY_DIVERTED in key.mapping_flags) == (rawXY_reporting and hidpp20.KeyFlag.RAW_XY in key.flags)
if remap in key.remappable_to or remap == 0: if remap in key.remappable_to or remap == 0:
key.remap(remap) key.remap(remap)