settings: implement and test per-key lighting
This commit is contained in:
parent
04a818f215
commit
1ed5f765e3
|
@ -45,6 +45,7 @@ from .settings import BitFieldWithOffsetAndMaskValidator as _BitFieldOMV
|
||||||
from .settings import ChoicesMapValidator as _ChoicesMapV
|
from .settings import ChoicesMapValidator as _ChoicesMapV
|
||||||
from .settings import ChoicesValidator as _ChoicesV
|
from .settings import ChoicesValidator as _ChoicesV
|
||||||
from .settings import FeatureRW as _FeatureRW
|
from .settings import FeatureRW as _FeatureRW
|
||||||
|
from .settings import FeatureRWMap as _FeatureRWMap
|
||||||
from .settings import HeteroValidator as _HeteroV
|
from .settings import HeteroValidator as _HeteroV
|
||||||
from .settings import LongSettings as _LongSettings
|
from .settings import LongSettings as _LongSettings
|
||||||
from .settings import MultipleRangeValidator as _MultipleRangeV
|
from .settings import MultipleRangeValidator as _MultipleRangeV
|
||||||
|
@ -1573,6 +1574,61 @@ class RGBEffectSetting(LEDZoneSetting):
|
||||||
return cls.setup(device, 0xE0, 0x10, b"\x01")
|
return cls.setup(device, 0xE0, 0x10, b"\x01")
|
||||||
|
|
||||||
|
|
||||||
|
class PerKeyLighting(_Settings):
|
||||||
|
name = "per-key-lighting"
|
||||||
|
label = _("Per-key Lighting")
|
||||||
|
description = _("Control per-key lighting.")
|
||||||
|
feature = _F.PER_KEY_LIGHTING_V2
|
||||||
|
keys_universe = _NamedInts.range(1, 254)
|
||||||
|
choices_universe = _special_keys.COLORS
|
||||||
|
|
||||||
|
def read(self, cached=True):
|
||||||
|
self._pre_read(cached)
|
||||||
|
if cached and self._value is not None:
|
||||||
|
return self._value
|
||||||
|
reply_map = {}
|
||||||
|
for key in self._validator.choices:
|
||||||
|
reply_map[int(key)] = 0xFFFFFF # can't read so fake a value of white
|
||||||
|
self._value = reply_map
|
||||||
|
return reply_map
|
||||||
|
|
||||||
|
def write(self, map, save=True):
|
||||||
|
if self._device.online:
|
||||||
|
self.update(map, save)
|
||||||
|
data_bytes = b""
|
||||||
|
for key, value in map.items():
|
||||||
|
data_bytes += key.to_bytes(1, "big") + value.to_bytes(3, "big")
|
||||||
|
if len(data_bytes) >= 16: # up to four values are packed into a request
|
||||||
|
self._device.feature_request(self.feature, 0x10, data_bytes)
|
||||||
|
data_bytes = b""
|
||||||
|
if len(data_bytes) > 0:
|
||||||
|
self._device.feature_request(self.feature, 0x10, data_bytes)
|
||||||
|
self._device.feature_request(self.feature, 0x70, 0x00) # signal device to make the changes
|
||||||
|
return map
|
||||||
|
|
||||||
|
def write_key_value(self, key, value, save=True):
|
||||||
|
result = super().write_key_value(key, value, save)
|
||||||
|
if self._device.online:
|
||||||
|
self._device.feature_request(self.feature, 0x70, 0x00) # signal device to make the change
|
||||||
|
return result
|
||||||
|
|
||||||
|
class rw_class(_FeatureRWMap):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class validator_class(_ChoicesMapV):
|
||||||
|
@classmethod
|
||||||
|
def build(cls, setting_class, device):
|
||||||
|
choices_map = {}
|
||||||
|
key_bitmap = device.feature_request(setting_class.feature, 0x00, 0x00, 0x00)[2:]
|
||||||
|
key_bitmap += device.feature_request(setting_class.feature, 0x00, 0x00, 0x01)[2:]
|
||||||
|
key_bitmap += device.feature_request(setting_class.feature, 0x00, 0x00, 0x02)[2:]
|
||||||
|
for i in range(1, 255):
|
||||||
|
if (key_bitmap[i // 8] >> i % 8) & 0x01:
|
||||||
|
choices_map[setting_class.keys_universe[i]] = setting_class.choices_universe
|
||||||
|
result = cls(choices_map) if choices_map else None
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
SETTINGS = [
|
SETTINGS = [
|
||||||
RegisterHandDetection, # simple
|
RegisterHandDetection, # simple
|
||||||
RegisterSmoothScroll, # simple
|
RegisterSmoothScroll, # simple
|
||||||
|
@ -1607,6 +1663,7 @@ SETTINGS = [
|
||||||
RGBControl,
|
RGBControl,
|
||||||
RGBEffectSetting,
|
RGBEffectSetting,
|
||||||
BrightnessControl,
|
BrightnessControl,
|
||||||
|
PerKeyLighting,
|
||||||
FnSwap, # simple
|
FnSwap, # simple
|
||||||
NewFnSwap, # simple
|
NewFnSwap, # simple
|
||||||
K375sFnSwap, # working
|
K375sFnSwap, # working
|
||||||
|
|
|
@ -610,6 +610,7 @@ responses_remappable_action = responses_reprog_controls + [
|
||||||
hidpp.Response("0051FF01005100", 0x0440, "0051FF01005100"), # right button set
|
hidpp.Response("0051FF01005100", 0x0440, "0051FF01005100"), # right button set
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
tests = [
|
tests = [
|
||||||
[
|
[
|
||||||
FeatureTest(
|
FeatureTest(
|
||||||
|
@ -642,6 +643,23 @@ tests = [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
+ responses_remappable_action,
|
+ responses_remappable_action,
|
||||||
|
[
|
||||||
|
FeatureTest(settings_templates.PerKeyLighting, {0x01: 0xFFFFFF, 0x02: 0xFFFFFF}, {0x02: 0xFF0000}, 0x70, "00"),
|
||||||
|
{
|
||||||
|
common.NamedInt(1, "1"): special_keys.COLORS,
|
||||||
|
common.NamedInt(2, "2"): special_keys.COLORS,
|
||||||
|
common.NamedInt(9, "9"): special_keys.COLORS,
|
||||||
|
common.NamedInt(10, "10"): special_keys.COLORS,
|
||||||
|
common.NamedInt(113, "113"): special_keys.COLORS,
|
||||||
|
common.NamedInt(114, "114"): special_keys.COLORS,
|
||||||
|
},
|
||||||
|
hidpp.Response("040001", 0x0000, "8081"), # PER_KEY_LIGHTING_V2
|
||||||
|
hidpp.Response("00000606000000000000000000000000", 0x0400, "0000"),
|
||||||
|
hidpp.Response("00000600000000000000000000000000", 0x0400, "0001"),
|
||||||
|
hidpp.Response("00000000000000000000000000000000", 0x0400, "0002"),
|
||||||
|
hidpp.Response("02FF0000", 0x0410, "02FF0000"),
|
||||||
|
hidpp.Response("00", 0x0470, "00"),
|
||||||
|
],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -651,7 +669,6 @@ def test_key_template(test, mocker):
|
||||||
spy_feature_request = mocker.spy(device, "feature_request")
|
spy_feature_request = mocker.spy(device, "feature_request")
|
||||||
|
|
||||||
setting = settings_templates.check_feature(device, test[0].sclass)
|
setting = settings_templates.check_feature(device, test[0].sclass)
|
||||||
print("SETTING", setting)
|
|
||||||
assert setting is not None
|
assert setting is not None
|
||||||
if isinstance(setting, list):
|
if isinstance(setting, list):
|
||||||
setting = setting[0]
|
setting = setting[0]
|
||||||
|
@ -664,6 +681,7 @@ def test_key_template(test, mocker):
|
||||||
value = setting.read(cached=False)
|
value = setting.read(cached=False)
|
||||||
for k, v in test[0].initial_value.items():
|
for k, v in test[0].initial_value.items():
|
||||||
assert value[k] == v
|
assert value[k] == v
|
||||||
|
setting.write(setting._value)
|
||||||
|
|
||||||
for key, value in test[0].write_value.items():
|
for key, value in test[0].write_value.items():
|
||||||
write_value = setting.write_key_value(key, value)
|
write_value = setting.write_key_value(key, value)
|
||||||
|
|
Loading…
Reference in New Issue