Solaar/tests/logitech_receiver/test_setting_templates.py

767 lines
32 KiB
Python

## Copyright (C) 2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""The tests work by creating a faked device (from the hidpp module) that uses provided data as responses to HID++ commands.
The device uses some methods from the real device to set up data structures that are needed for some tests.
"""
from dataclasses import dataclass
from typing import Any
import pytest
from logitech_receiver import common
from logitech_receiver import hidpp20
from logitech_receiver import hidpp20_constants
from logitech_receiver import settings_templates
from logitech_receiver import special_keys
from . import hidpp
# TODO action part of DpiSlidingXY, MouseGesturesXY
class Setup:
def __init__(self, test, *params):
self.test = test
self.responses = [r for r in params if isinstance(r, hidpp.Response)]
self.choices = None if isinstance(params[0], hidpp.Response) else params[0]
@dataclass
class RegisterTest:
sclass: Any
initial_value: Any = False
write_value: Any = True
write_params: str = "01"
register_tests = [
Setup(
RegisterTest(settings_templates.RegisterHandDetection, False, True, [b"\x00\x00\x00"]),
hidpp.Response("000030", 0x8101), # keyboard_hand_detection
hidpp.Response("000000", 0x8001, "000000"),
),
Setup(
RegisterTest(settings_templates.RegisterHandDetection, True, False, [b"\x00\x00\x30"]),
hidpp.Response("000000", 0x8101), # keyboard_hand_detection
hidpp.Response("000030", 0x8001, "000030"),
),
Setup(
RegisterTest(settings_templates.RegisterSmoothScroll, False, True, [b"\x40"]),
hidpp.Response("00", 0x8101), # mouse_button_flags
hidpp.Response("40", 0x8001, "40"),
),
Setup(
RegisterTest(settings_templates.RegisterSideScroll, True, False, [b"\x00"]),
hidpp.Response("02", 0x8101), # mouse_button_flags
hidpp.Response("00", 0x8001, "00"),
),
Setup(
RegisterTest(settings_templates.RegisterFnSwap, False, True, [b"\x00\x01"]),
hidpp.Response("0000", 0x8109), # keyboard_fn_swap
hidpp.Response("0001", 0x8009, "0001"),
),
Setup(
RegisterTest(
settings_templates._PerformanceMXDpi, common.NamedInt(0x88, "800"), common.NamedInt(0x89, "900"), [b"\x89"]
),
hidpp.Response("88", 0x8163), # mouse_dpi
hidpp.Response("89", 0x8063, "89"),
),
]
@pytest.mark.parametrize("test", register_tests)
def test_register_template(test, mocker):
device = hidpp.Device(protocol=1.0, responses=test.responses)
spy_request = mocker.spy(device, "request")
setting = test.test.sclass.build(device)
value = setting.read(cached=False)
cached_value = setting.read(cached=True)
write_value = setting.write(test.test.write_value)
assert setting is not None
assert value == test.test.initial_value
assert cached_value == test.test.initial_value
assert write_value == test.test.write_value
spy_request.assert_called_with(test.test.sclass.register + 0x8000, *test.test.write_params)
@dataclass
class FeatureTest:
sclass: Any
initial_value: Any = False
write_value: Any = True
matched_calls: int = 1
offset: int = 0x04
version: int = 0x00
simple_tests = [
Setup(
FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06),
hidpp.Response("FF0001", 0x0600, "FF"),
hidpp.Response("FF0101", 0x0610, "FF01"),
),
Setup(
FeatureTest(settings_templates.FnSwap, True, False),
hidpp.Response("01", 0x0400),
hidpp.Response("00", 0x0410, "00"),
),
Setup(
FeatureTest(settings_templates.NewFnSwap, True, False),
hidpp.Response("01", 0x0400),
hidpp.Response("00", 0x0410, "00"),
),
# Setup( # Backlight has caused problems
# FeatureTest(settings_templates.Backlight, 0, 5, offset=0x06),
# hidpp.Response("00", 0x0600),
# hidpp.Response("05", 0x0610, "05"),
# ),
Setup(
FeatureTest(settings_templates.Backlight2DurationHandsOut, 80, 160, version=0x03),
hidpp.Response("011830000000100040006000", 0x0400),
hidpp.Response("0118FF00200040006000", 0x0410, "0118FF00200040006000"),
),
Setup(
FeatureTest(settings_templates.Backlight2DurationHandsIn, 320, 160, version=0x03),
hidpp.Response("011830000000200040006000", 0x0400),
hidpp.Response("0118FF00200020006000", 0x0410, "0118FF00200020006000"),
),
Setup(
FeatureTest(settings_templates.Backlight2DurationPowered, 480, 80, version=0x03),
hidpp.Response("011830000000200040006000", 0x0400),
hidpp.Response("0118FF00200040001000", 0x0410, "0118FF00200040001000"),
),
Setup(
FeatureTest(settings_templates.Backlight3, 0x50, 0x70),
hidpp.Response("50", 0x0410),
hidpp.Response("70", 0x0420, "007009"),
),
Setup(
FeatureTest(settings_templates.HiResScroll, True, False),
hidpp.Response("01", 0x0400),
hidpp.Response("00", 0x0410, "00"),
),
Setup(
FeatureTest(settings_templates.LowresMode, False, True),
hidpp.Response("00", 0x0400),
hidpp.Response("01", 0x0410, "01"),
),
Setup(
FeatureTest(settings_templates.HiresSmoothInvert, True, False),
hidpp.Response("06", 0x0410),
hidpp.Response("02", 0x0420, "02"),
),
Setup(
FeatureTest(settings_templates.HiresSmoothResolution, True, False),
hidpp.Response("06", 0x0410),
hidpp.Response("04", 0x0420, "04"),
),
Setup(
FeatureTest(settings_templates.HiresMode, False, True),
hidpp.Response("06", 0x0410),
hidpp.Response("07", 0x0420, "07"),
),
Setup(
FeatureTest(settings_templates.PointerSpeed, 0x0100, 0x0120),
hidpp.Response("0100", 0x0400),
hidpp.Response("0120", 0x0410, "0120"),
),
Setup(
FeatureTest(settings_templates.ThumbMode, True, False),
hidpp.Response("0100", 0x0410),
hidpp.Response("0000", 0x0420, "0000"),
),
Setup(
FeatureTest(settings_templates.ThumbInvert, False, True),
hidpp.Response("0100", 0x0410),
hidpp.Response("0101", 0x0420, "0101"),
),
Setup(
FeatureTest(settings_templates.DivertCrown, False, True),
hidpp.Response("01", 0x0410),
hidpp.Response("02", 0x0420, "02"),
),
Setup(
FeatureTest(settings_templates.CrownSmooth, True, False),
hidpp.Response("0001", 0x0410),
hidpp.Response("0002", 0x0420, "0002"),
),
Setup(
FeatureTest(settings_templates.DivertGkeys, False, True),
hidpp.Response("01", 0x0420, "01"),
),
Setup(
FeatureTest(settings_templates.ScrollRatchet, 2, 1),
hidpp.Response("02", 0x0400),
hidpp.Response("01", 0x0410, "01"),
),
Setup(
FeatureTest(settings_templates.SmartShift, 1, 10),
hidpp.Response("0100", 0x0400),
hidpp.Response("000A", 0x0410, "000A"),
),
Setup(
FeatureTest(settings_templates.SmartShift, 5, 50),
hidpp.Response("0005", 0x0400),
hidpp.Response("00FF", 0x0410, "00FF"),
),
Setup(
FeatureTest(settings_templates.SmartShiftEnhanced, 5, 50),
hidpp.Response("0005", 0x0410),
hidpp.Response("00FF", 0x0420, "00FF"),
),
Setup(
FeatureTest(settings_templates.DisableKeyboardKeys, {1: True, 8: True}, {1: False, 8: True}),
hidpp.Response("09", 0x0400),
hidpp.Response("09", 0x0410),
hidpp.Response("08", 0x0420, "08"),
),
Setup(
FeatureTest(settings_templates.DualPlatform, 0, 1),
hidpp.Response("00", 0x0400),
hidpp.Response("01", 0x0420, "01"),
),
Setup(
FeatureTest(settings_templates.MKeyLEDs, {1: False, 2: False, 4: False}, {1: False, 2: True, 4: True}),
hidpp.Response("03", 0x0400),
hidpp.Response("06", 0x0410, "06"),
),
Setup(
FeatureTest(settings_templates.MRKeyLED, False, True),
hidpp.Response("01", 0x0400, "01"),
),
Setup(
FeatureTest(settings_templates.Sidetone, 5, 0xA),
hidpp.Response("05", 0x0400),
hidpp.Response("0A", 0x0410, "0A"),
),
Setup(
FeatureTest(settings_templates.ADCPower, 5, 0xA),
hidpp.Response("05", 0x0410),
hidpp.Response("0A", 0x0420, "0A"),
),
Setup(
FeatureTest(settings_templates.LEDControl, 0, 1),
hidpp.Response("00", 0x0470),
hidpp.Response("01", 0x0480, "01"),
),
Setup(
FeatureTest(
settings_templates.LEDZoneSetting,
hidpp20.LEDEffectSetting(ID=3, intensity=0x50, period=0x100),
hidpp20.LEDEffectSetting(ID=3, intensity=0x50, period=0x101),
),
hidpp.Response("0100000001", 0x0400),
hidpp.Response("00000102", 0x0410, "00FF00"),
hidpp.Response("0000000300040005", 0x0420, "000000"),
hidpp.Response("0001000B00080009", 0x0420, "000100"),
hidpp.Response("000000000000010050", 0x04E0, "00"),
hidpp.Response("000000000000000101500000", 0x0430, "000000000000000101500000"),
),
Setup(
FeatureTest(settings_templates.RGBControl, 0, 1),
hidpp.Response("0000", 0x0450),
hidpp.Response("010100", 0x0450, "0101"),
),
Setup(
FeatureTest(
settings_templates.RGBEffectSetting,
hidpp20.LEDEffectSetting(ID=3, intensity=0x50, period=0x100),
hidpp20.LEDEffectSetting(ID=2, color=0x505050, speed=0x50),
),
hidpp.Response("FFFF0100000001", 0x0400, "FFFF00"),
hidpp.Response("0000000102", 0x0400, "00FF00"),
hidpp.Response("0000000300040005", 0x0400, "000000"),
hidpp.Response("0001000200080009", 0x0400, "000100"),
hidpp.Response("000000000000010050", 0x04E0, "00"),
hidpp.Response("00015050505000000000000001", 0x0410, "00015050505000000000000001"),
),
Setup(
FeatureTest(settings_templates.RGBEffectSetting, None, hidpp20.LEDEffectSetting(ID=3, intensity=0x60, period=0x101)),
hidpp.Response("FFFF0100000001", 0x0400, "FFFF00"),
hidpp.Response("0000000102", 0x0400, "00FF00"),
hidpp.Response("0000000300040005", 0x0400, "000000"),
hidpp.Response("0001000200080009", 0x0400, "000100"),
hidpp.Response("00000000000000010160000001", 0x0410, "00000000000000010160000001"),
),
Setup(
FeatureTest(settings_templates.RGBEffectSetting, None, hidpp20.LEDEffectSetting(ID=3, intensity=0x60, period=0x101)),
hidpp.Response("FF000200020004000000000000000000", 0x0400, "FFFF00"),
hidpp.Response("00000002040000000000000000000000", 0x0400, "00FF00"),
hidpp.Response("00000000000000000000000000000000", 0x0400, "000000"),
hidpp.Response("00010001000000000000000000000000", 0x0400, "000100"),
hidpp.Response("00020003C00503E00000000000000000", 0x0400, "000200"),
hidpp.Response("0003000AC0011E0B0000000000000000", 0x0400, "000300"),
hidpp.Response("01000001070000000000000000000000", 0x0400, "01FF00"),
hidpp.Response("01000000000000000000000000000000", 0x0400, "010000"),
hidpp.Response("01010001000000000000000000000000", 0x0400, "010100"),
hidpp.Response("0102000AC0011E0B0000000000000000", 0x0400, "010200"),
hidpp.Response("01030003C00503E00000000000000000", 0x0400, "010300"),
hidpp.Response("01040004DCE1001E0000000000000000", 0x0400, "010400"),
hidpp.Response("0105000B000000320000000000000000", 0x0400, "010500"),
hidpp.Response("0106000C001B02340000000000000000", 0x0400, "010600"),
hidpp.Response("00020000000000010160000001", 0x0410, "00020000000000010160000001"),
),
Setup(
FeatureTest(settings_templates.Backlight2, 0xFF, 0x00),
common.NamedInts(Disabled=0xFF, Enabled=0x00),
hidpp.Response("000201000000000000000000", 0x0400),
hidpp.Response("010201", 0x0410, "0102FF00000000000000"),
),
Setup(
FeatureTest(settings_templates.Backlight2, 0x03, 0xFF),
common.NamedInts(Disabled=0xFF, Automatic=0x01, Manual=0x03),
hidpp.Response("011838000000000000000000", 0x0400),
hidpp.Response("001801", 0x0410, "0018FF00000000000000"),
),
Setup(
FeatureTest(settings_templates.Backlight2Level, 0, 3, version=0x03),
[0, 4],
hidpp.Response("011830000000000000000000", 0x0400),
hidpp.Response("05", 0x0420),
hidpp.Response("01180103000000000000", 0x0410, "0118FF03000000000000"),
),
Setup(
FeatureTest(settings_templates.Backlight2Level, 0, 2, version=0x03),
[0, 4],
hidpp.Response("011830000000000000000000", 0x0400),
hidpp.Response("05", 0x0420),
hidpp.Response("01180102000000000000", 0x0410, "0118FF02000000000000"),
),
Setup(
FeatureTest(settings_templates.OnboardProfiles, 0, 1, offset=0x0C),
common.NamedInts(**{"Disabled": 0, "Profile 1": 1, "Profile 2": 2}),
hidpp.Response("00010100000201FFFFFFFFFFFFFFFFFF", 0x0C50, "00000000"),
hidpp.Response("000201FFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000004"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000008"),
hidpp.Response("02", 0x0C20),
hidpp.Response("01", 0x0C10, "01"),
hidpp.Response("0001", 0x0C30, "0001"),
),
Setup(
FeatureTest(settings_templates.OnboardProfiles, 1, 0, offset=0x0C),
common.NamedInts(**{"Disabled": 0, "Profile 1": 1, "Profile 2": 2}),
hidpp.Response("00010100000201FFFFFFFFFFFFFFFFFF", 0x0C50, "00000000"),
hidpp.Response("000201FFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000004"),
hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000008"),
hidpp.Response("01", 0x0C20),
hidpp.Response("0001", 0x0C40),
hidpp.Response("02", 0x0C10, "02"),
),
Setup(
FeatureTest(settings_templates.ReportRate, 1, 5, offset=0x0C),
common.NamedInts(**{"1ms": 1, "2ms": 2, "5ms": 5, "6ms": 6}),
hidpp.Response("33", 0x0C00),
hidpp.Response("01", 0x0C10),
hidpp.Response("05", 0x0C20, "05"),
),
Setup(
FeatureTest(settings_templates.ExtendedReportRate, 1, 5, offset=0x0C),
common.NamedInts(**{"8ms": 0, "4ms": 1, "500us": 4, "250us": 5}),
hidpp.Response("33", 0x0C10),
hidpp.Response("01", 0x0C20),
hidpp.Response("05", 0x0C30, "05"),
),
Setup(
FeatureTest(settings_templates.AdjustableDpi, 800, 400, version=0x03),
common.NamedInts.list([400, 800, 1600]),
hidpp.Response("000190032006400000", 0x0410, "000000"),
hidpp.Response("000320", 0x0420),
hidpp.Response("000190", 0x0430, "000190"),
),
Setup(
FeatureTest(settings_templates.AdjustableDpi, 256, 512, version=0x03),
common.NamedInts.list([256, 512]),
hidpp.Response("000100e10002000000", 0x0410, "000000"),
hidpp.Response("000100", 0x0420),
hidpp.Response("000200", 0x0430, "000200"),
),
Setup(
FeatureTest(settings_templates.AdjustableDpi, 400, 800, version=0x03),
common.NamedInts.list([400, 800, 1200, 1600]),
hidpp.Response("000190E19006400000000000000000", 0x0410, "000000"),
hidpp.Response("000190", 0x0420),
hidpp.Response("000320", 0x0430, "000320"),
),
Setup(
FeatureTest(settings_templates.Multiplatform, 0, 1),
common.NamedInts(**{"MacOS 0.1-0.5": 0, "iOS 0.1-0.7": 1, "Linux 0.2-0.9": 2, "Windows 0.3-0.9": 3}),
hidpp.Response("020004000001", 0x0400),
hidpp.Response("00FF200000010005", 0x0410, "00"),
hidpp.Response("01FF400000010007", 0x0410, "01"),
hidpp.Response("02FF040000020009", 0x0410, "02"),
hidpp.Response("03FF010000030009", 0x0410, "03"),
hidpp.Response("FF01", 0x0430, "FF01"),
),
Setup(
FeatureTest(settings_templates.ChangeHost, 1, 0),
common.NamedInts(**{"1:ABCDEF": 0, "2:GHIJKL": 1}),
hidpp.Response("050003", 0x0000, "1815"), # HOSTS_INFO
hidpp.Response("01000200", 0x0500),
hidpp.Response("000100000600", 0x0510, "00"),
hidpp.Response("000041424344454600", 0x0530, "0000"),
hidpp.Response("000100000600", 0x0510, "01"),
hidpp.Response("00004748494A4B4C00", 0x0530, "0100"),
hidpp.Response("0201", 0x0400),
hidpp.Response(True, 0x0410, "00"),
),
Setup(
FeatureTest(settings_templates.BrightnessControl, 0x10, 0x20),
[0, 80],
hidpp.Response("00505100000000", 0x0400), # 0 to 80, all acceptable, no separate on/off
hidpp.Response("10", 0x0410), # brightness 16
hidpp.Response("0020", 0x0420, "0020"), # set brightness 32
),
Setup(
FeatureTest(settings_templates.BrightnessControl, 0x10, 0x00),
[0, 80],
hidpp.Response("00505104000000", 0x0400), # 0 to 80, all acceptable, separate on/off
hidpp.Response("10", 0x0410), # brightness 16
hidpp.Response("01", 0x0430), # on
hidpp.Response("00", 0x0440), # set off
hidpp.Response("0000", 0x0420, "0000"), # set brightness 0
),
Setup(
FeatureTest(settings_templates.BrightnessControl, 0x00, 0x20),
[0, 80],
hidpp.Response("00505104000000", 0x0400), # 0 to 80, all acceptable, separate on/off
hidpp.Response("10", 0x0410), # brightness 16
hidpp.Response("00", 0x0430), # off
hidpp.Response("01", 0x0440), # set on
hidpp.Response("0020", 0x0420, "0020"), # set brightness 32
),
Setup(
FeatureTest(settings_templates.BrightnessControl, 0x20, 0x08),
[0, 80],
hidpp.Response("00504104001000", 0x0400), # 16 to 80, all acceptable, separate on/off
hidpp.Response("20", 0x0410), # brightness 32
hidpp.Response("01", 0x0430), # on
hidpp.Response("00", 0x0440, "00"), # set off
),
Setup(
FeatureTest(settings_templates.SpeedChange, 0, None, 0), # need to set up all settings to successfully write
common.NamedInts(**{"Off": 0, "DPI Change": 0xED}),
*hidpp.responses_speedchange,
),
]
@pytest.fixture
def mock_gethostname(mocker):
mocker.patch("socket.gethostname", return_value="ABCDEF.foo.org")
@pytest.mark.parametrize("test", simple_tests)
def test_simple_template(test, mocker, mock_gethostname):
tst = test.test
device = hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version)
spy_request = mocker.spy(device, "request")
setting = settings_templates.check_feature(device, tst.sclass)
assert setting is not None
if isinstance(setting, list):
setting = setting[0]
if isinstance(test.choices, list):
assert setting._validator.min_value == test.choices[0]
assert setting._validator.max_value == test.choices[1]
elif test.choices is not None:
assert setting.choices == test.choices
value = setting.read(cached=False)
assert value == tst.initial_value
cached_value = setting.read(cached=True)
assert cached_value == tst.initial_value
write_value = setting.write(tst.write_value) if tst.write_value is not None else None
assert write_value == tst.write_value
hidpp.match_requests(tst.matched_calls, test.responses, spy_request.call_args_list)
responses_reprog_controls = [
hidpp.Response("03", 0x0500),
hidpp.Response("00500038010001010400000000000000", 0x0510, "00"), # left button
hidpp.Response("00510039010001010400000000000000", 0x0510, "01"), # right button
hidpp.Response("00C4009D310003070500000000000000", 0x0510, "02"), # smart shift
hidpp.Response("00500000000000000000000000000000", 0x0520, "0050"), # left button current
hidpp.Response("00510000500000000000000000000000", 0x0520, "0051"), # right button current
hidpp.Response("00C40000000000000000000000000000", 0x0520, "00C4"), # smart shift current
hidpp.Response("00500005000000000000000000000000", 0x0530, "0050000050"), # left button write
hidpp.Response("00510005000000000000000000000000", 0x0530, "0051000050"), # right button write
hidpp.Response("00C4000C400000000000000000000000", 0x0530, "00C40000C4"), # smart shift write
]
key_tests = [
Setup(
FeatureTest(settings_templates.ReprogrammableKeys, {0x50: 0x50, 0x51: 0x50, 0xC4: 0xC4}, {0x51: 0x51}, 4, offset=0x05),
{
common.NamedInt(0x50, "Left Button"): common.UnsortedNamedInts(Left_Click=0x50, Right_Click=0x51),
common.NamedInt(0x51, "Right Button"): common.UnsortedNamedInts(Right_Click=0x51, Left_Click=0x50),
common.NamedInt(0xC4, "Smart Shift"): common.UnsortedNamedInts(Smart_Shift=0xC4, Left_Click=80, Right_Click=81),
},
*responses_reprog_controls,
hidpp.Response("0051000051", 0x0530, "0051000051"), # right button set write
),
Setup(
FeatureTest(settings_templates.DivertKeys, {0xC4: 0}, {0xC4: 1}, 2, offset=0x05),
{common.NamedInt(0xC4, "Smart Shift"): common.NamedInts(Regular=0, Diverted=1, Mouse_Gestures=2)},
*responses_reprog_controls,
hidpp.Response("00C4020000", 0x0530, "00C4020000"), # Smart Shift write
hidpp.Response("00C4030000", 0x0530, "00C4030000"), # Smart Shift divert write
),
Setup(
FeatureTest(settings_templates.DivertKeys, {0xC4: 0}, {0xC4: 2}, 2, offset=0x05),
{common.NamedInt(0xC4, "Smart Shift"): common.NamedInts(Regular=0, Diverted=1, Mouse_Gestures=2, Sliding_DPI=3)},
*responses_reprog_controls,
hidpp.Response("0A0001", 0x0000, "2201"), # ADJUSTABLE_DPI
hidpp.Response("00C4300000", 0x0530, "00C4300000"), # Smart Shift write
hidpp.Response("00C4030000", 0x0530, "00C4030000"), # Smart Shift divert write
),
Setup(
FeatureTest(settings_templates.PersistentRemappableAction, {80: 16797696, 81: 16797696}, {0x51: 16797952}, 3),
{
common.NamedInt(80, "Left Button"): special_keys.KEYS_KEYS_CONSUMER,
common.NamedInt(81, "Right Button"): special_keys.KEYS_KEYS_CONSUMER,
},
hidpp.Response("050001", 0x0000, "1B04"), # REPROG_CONTROLS_V4
*responses_reprog_controls,
hidpp.Response("0041", 0x0400),
hidpp.Response("0201", 0x0410),
hidpp.Response("02", 0x0400),
hidpp.Response("0050", 0x0420, "00FF"), # left button
hidpp.Response("0051", 0x0420, "01FF"), # right button
hidpp.Response("0050000100500000", 0x0430, "0050FF"), # left button current
hidpp.Response("0051000100500001", 0x0430, "0051FF"), # right button current
hidpp.Response("0050FF01005000", 0x0440, "0050FF01005000"), # left button write
hidpp.Response("0051FF01005000", 0x0440, "0051FF01005000"), # right button write
hidpp.Response("0051FF01005100", 0x0440, "0051FF01005100"), # right button set write
),
Setup(
FeatureTest(
settings_templates.Gesture2Gestures,
{
1: True,
2: True,
30: True,
10: True,
45: False,
42: True,
43: True,
64: False,
65: False,
67: False,
84: True,
34: False,
},
{45: True},
4,
),
*hidpp.responses_gestures,
hidpp.Response("0001FF6F", 0x0420, "0001FF6F"), # write
hidpp.Response("01010F04", 0x0420, "01010F04"),
hidpp.Response("0001FF7F", 0x0420, "0001FF7F"), # write 45
hidpp.Response("01010F04", 0x0420, "01010F04"),
),
Setup(
FeatureTest(
settings_templates.Gesture2Divert,
{1: False, 2: False, 10: False, 44: False, 64: False, 65: False, 67: False, 84: False, 85: False, 100: False},
{44: True},
4,
),
*hidpp.responses_gestures,
hidpp.Response("0001FF00", 0x0440, "0001FF00"), # write
hidpp.Response("01010300", 0x0440, "01010300"),
hidpp.Response("0001FF08", 0x0440, "0001FF08"), # write 44
hidpp.Response("01010300", 0x0440, "01010300"),
),
Setup(
FeatureTest(
settings_templates.Gesture2Params,
{4: {"scale": 256}},
{4: {"scale": 128}},
2,
),
*hidpp.responses_gestures,
hidpp.Response("000100FF000000000000000000000000", 0x0480, "000100FF"),
hidpp.Response("000080FF000000000000000000000000", 0x0480, "000080FF"),
),
Setup(
FeatureTest(settings_templates.Equalizer, {0: -0x20, 1: 0x10}, {1: 0x18}, 2),
[-32, 32],
hidpp.Response("0220000000", 0x0400),
hidpp.Response("0000800100000000000000", 0x0410, "00"),
hidpp.Response("E010", 0x0420, "00"),
hidpp.Response("E010", 0x0430, "02E010"),
hidpp.Response("E018", 0x0430, "02E018"),
),
Setup(
FeatureTest(
settings_templates.PerKeyLighting,
{1: 0xFFFFFF, 2: 0xFFFFFF, 9: 0xFFFFFF, 10: 0xFFFFFF, 113: 0xFFFFFF, 114: 0xFFFFFF},
{2: 0xFF0000},
5,
),
{
common.NamedInt(1, "A"): special_keys.COLORS,
common.NamedInt(2, "B"): special_keys.COLORS,
common.NamedInt(9, "I"): special_keys.COLORS,
common.NamedInt(10, "J"): special_keys.COLORS,
common.NamedInt(113, "KEY 113"): special_keys.COLORS,
common.NamedInt(114, "KEY 114"): special_keys.COLORS,
},
hidpp.Response("00000606000000000000000000000000", 0x0400, "0000"), # first group of keys
hidpp.Response("00000600000000000000000000000000", 0x0400, "0001"), # second group of keys
hidpp.Response("00000000000000000000000000000000", 0x0400, "0002"), # last group of keys
hidpp.Response("01FFFFFF02FFFFFF09FFFFFF0AFFFFFF", 0x0410, "01FFFFFF02FFFFFF09FFFFFF0AFFFFFF"), # write first 4 values
hidpp.Response("71FFFFFF72FFFFFF", 0x0410, "71FFFFFF72FFFFFF"), # write last two values
hidpp.Response("00", 0x0470, "00"), # finish
hidpp.Response("02FF0000", 0x0410, "02FF0000"), # write one value
hidpp.Response("00", 0x0470, "00"), # finish
),
Setup(
FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 256}, {0: 512}, 2, offset=0x9),
{common.NamedInt(0, "X"): common.NamedInts.list([256, 512])},
hidpp.Response("000000", 0x0910, "00"), # no y direction, no lod
hidpp.Response("0000000100e10002000000", 0x0920, "000000"),
hidpp.Response("00010000000000000000", 0x0950),
hidpp.Response("000100000000", 0x0960, "000100000000"),
hidpp.Response("000200000000", 0x0960, "000200000000"),
),
Setup(
FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 0x64, 1: 0xE4}, {0: 0x164}, 2, offset=0x9),
{
common.NamedInt(0, "X"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164, 0x01C4]),
common.NamedInt(1, "Y"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164]),
},
hidpp.Response("000001", 0x0910, "00"), # supports y direction, no lod
hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000000"),
hidpp.Response("000001E4E0400124E0400164E06001C4", 0x0920, "000001"),
hidpp.Response("00000000000000000000000000000000", 0x0920, "000002"),
hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000100"),
hidpp.Response("000001E4E0400124E040016400000000", 0x0920, "000101"),
hidpp.Response("000064007400E4007400", 0x0950),
hidpp.Response("00006400E400", 0x0960, "00006400E400"),
hidpp.Response("00016400E400", 0x0960, "00016400E400"),
),
Setup(
FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 0x64, 1: 0xE4, 2: 1}, {1: 0x164}, 2, offset=0x9),
{
common.NamedInt(0, "X"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164, 0x01C4]),
common.NamedInt(1, "Y"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164]),
common.NamedInt(2, "LOD"): common.NamedInts(LOW=0, MEDIUM=1, HIGH=2),
},
hidpp.Response("000003", 0x0910, "00"), # supports y direction and lod
hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000000"),
hidpp.Response("000001E4E0400124E0400164E06001C4", 0x0920, "000001"),
hidpp.Response("00000000000000000000000000000000", 0x0920, "000002"),
hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000100"),
hidpp.Response("000001E4E0400124E040016400000000", 0x0920, "000101"),
hidpp.Response("000064007400E4007401", 0x0950),
hidpp.Response("00006400E401", 0x0960, "00006400E401"),
hidpp.Response("000064016401", 0x0960, "000064016401"),
),
]
@pytest.mark.parametrize("test", key_tests)
def test_key_template(test, mocker):
tst = test.test
device = hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version)
spy_request = mocker.spy(device, "request")
setting = settings_templates.check_feature(device, tst.sclass)
assert setting is not None
if isinstance(setting, list):
setting = setting[0]
if isinstance(test.choices, list):
assert setting._validator.min_value == test.choices[0]
assert setting._validator.max_value == test.choices[1]
elif test.choices is not None:
assert setting.choices == test.choices
value = setting.read(cached=False)
assert value == tst.initial_value
write_value = setting.write(value)
assert write_value == tst.initial_value
for key, value in tst.write_value.items():
write_value = setting.write_key_value(key, value)
assert write_value == value
hidpp.match_requests(tst.matched_calls, test.responses, spy_request.call_args_list)
@pytest.mark.parametrize(
"responses, currentSpeed, newSpeed",
[
(hidpp.responses_speedchange, 100, 200),
(hidpp.responses_speedchange, None, 250),
],
)
def test_SpeedChange_action(responses, currentSpeed, newSpeed, mocker):
device = hidpp.Device(responses=responses, feature=hidpp20_constants.FEATURE.POINTER_SPEED)
spy_setting_callback = mocker.spy(device, "setting_callback")
settings_templates.check_feature_settings(device, device.settings) # need to set up all the settings
device.persister = {"pointer_speed": currentSpeed, "_speed-change": newSpeed}
speed_setting = next(filter(lambda s: s.name == "speed-change", device.settings), None)
pointer_setting = next(filter(lambda s: s.name == "pointer_speed", device.settings), None)
speed_setting.write(237)
speed_setting._rw.press_action()
if newSpeed is not None and speed_setting is not None:
spy_setting_callback.assert_any_call(device, type(pointer_setting), [newSpeed])
assert device.persister["_speed-change"] == currentSpeed
assert device.persister["pointer_speed"] == newSpeed
@pytest.mark.parametrize("test", simple_tests + key_tests)
def test_check_feature_settings(test, mocker):
tst = test.test
device = hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version)
already_known = []
setting = settings_templates.check_feature_settings(device, already_known)
assert setting is True
assert already_known
@pytest.mark.parametrize(
"test",
[
Setup(
FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06),
hidpp.Response("FF0001", 0x0600, "FF"),
hidpp.Response("FF0101", 0x0610, "FF01"),
)
],
)
def test_check_feature_setting(test, mocker):
tst = test.test
device = hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version)
setting = settings_templates.check_feature_setting(device, tst.sclass.name)
assert setting