## 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