425 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			425 lines
		
	
	
		
			21 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.
 | |
| 
 | |
| """HID++ data and functions common to several logitech_receiver test files"""
 | |
| 
 | |
| 
 | |
| import errno
 | |
| import threading
 | |
| 
 | |
| from dataclasses import dataclass
 | |
| from dataclasses import field
 | |
| from struct import pack
 | |
| from typing import Any
 | |
| from typing import Optional
 | |
| 
 | |
| from logitech_receiver import device
 | |
| from logitech_receiver import hidpp20
 | |
| from solaar import configuration
 | |
| 
 | |
| 
 | |
| def open_path(path: Optional[str]) -> int:
 | |
|     if path is None:
 | |
|         raise OSError(errno.EACCES, "Fake access error")
 | |
|     return int(path, 16)  # can raise exception
 | |
| 
 | |
| 
 | |
| def ping(responses, handle, devnumber, long_message=False):
 | |
|     for r in responses:
 | |
|         if handle == r.handle and devnumber == r.devnumber and r.id == 0x0010:
 | |
|             return r.response
 | |
| 
 | |
| 
 | |
| def request(responses, handle, devnumber, id, *params, no_reply=False, return_error=False, long_message=False, protocol=1.0):
 | |
|     params = b"".join(pack("B", p) if isinstance(p, int) else p for p in params)
 | |
|     print("REQUEST ", hex(handle), hex(devnumber), hex(id), params.hex())
 | |
|     for r in responses:
 | |
|         if handle == r.handle and devnumber == r.devnumber and r.id == id and bytes.fromhex(r.params) == params:
 | |
|             print("RESPONSE", hex(r.handle), hex(r.devnumber), hex(r.id), r.params, r.response)
 | |
|             return bytes.fromhex(r.response) if r.response is not None else None
 | |
| 
 | |
| 
 | |
| @dataclass
 | |
| class Response:
 | |
|     response: Optional[str]
 | |
|     id: int
 | |
|     params: str = ""
 | |
|     handle: int = 0x11
 | |
|     devnumber: int = 0xFF
 | |
|     no_reply: bool = False
 | |
| 
 | |
| 
 | |
| def replace_number(responses, number):  # change the devnumber for a list of responses
 | |
|     return [Response(r.response, r.id, r.params, r.handle, number, r.no_reply) for r in responses]
 | |
| 
 | |
| 
 | |
| def adjust_responses_index(index, responses):  # change index-4 responses to index
 | |
|     return [Response(r.response, r.id - 0x400 + (index << 8), r.params, r.handle, r.devnumber, r.no_reply) for r in responses]
 | |
| 
 | |
| 
 | |
| r_empty = [  # a HID++ device with no responses except for ping
 | |
|     Response(1.0, 0x0010),  # ping
 | |
| ]
 | |
| 
 | |
| r_keyboard_1 = [  # a HID++ 1.0 keyboard
 | |
|     Response(1.0, 0x0010),  # ping
 | |
|     Response("001234", 0x81F1, "01"),  # firmware
 | |
|     Response("003412", 0x81F1, "02"),  # firmware
 | |
|     Response("002345", 0x81F1, "03"),  # firmware
 | |
|     Response("003456", 0x81F1, "04"),  # firmware
 | |
|     Response("050050", 0x8107),  # battery status
 | |
| ]
 | |
| 
 | |
| r_keyboard_2 = [  # a HID++ 2.0 keyboard
 | |
|     Response(4.2, 0x0010),  # ping
 | |
|     Response("010001", 0x0000, "0001"),  # feature set at 0x01
 | |
|     Response("020003", 0x0000, "0020"),  # CONFIG_CHANGE at 0x02
 | |
|     Response("030001", 0x0000, "0003"),  # device information at 0x03
 | |
|     Response("040003", 0x0000, "0100"),  # unknown 0100 at 0x04
 | |
|     Response("050003", 0x0000, "1B04"),  # reprogrammable keys V4 at 0x05
 | |
|     Response("060003", 0x0000, "0007"),  # device friendly name at 0x06
 | |
|     Response("070003", 0x0000, "0005"),  # device name at 0x07
 | |
|     Response("080003", 0x0000, "1000"),  # battery status at 0x08
 | |
|     Response("08", 0x0100),  # 8 features
 | |
|     Response("00010001", 0x0110, "01"),  # feature set at 0x01
 | |
|     Response("00200003", 0x0110, "02"),  # CONFIG_CHANGE at 0x02
 | |
|     Response("00030001", 0x0110, "03"),  # device information at 0x03
 | |
|     Response("01000003", 0x0110, "04"),  # unknown 0100 at 0x04
 | |
|     Response("1B040003", 0x0110, "05"),  # reprogrammable keys V4 at 0x05
 | |
|     Response("00070003", 0x0000, "06"),  # device friendly name at 0x06
 | |
|     Response("00050003", 0x0000, "07"),  # device name at 0x07
 | |
|     Response("10000001", 0x0110, "08"),  # battery status at 0x02
 | |
|     Response("0212345678000D1234567890ABAA01", 0x0300),  # device information
 | |
|     Response("04", 0x0500),  # reprogrammable keys V4
 | |
|     Response("00110012AB010203CD00", 0x0510, "00"),  # reprogrammable keys V4
 | |
|     Response("01110022AB010203CD00", 0x0510, "01"),  # reprogrammable keys V4
 | |
|     Response("00010111AB010203CD00", 0x0510, "02"),  # reprogrammable keys V4
 | |
|     Response("03110032AB010204CD00", 0x0510, "03"),  # reprogrammable keys V4
 | |
|     Response("00030333AB010203CD00", 0x0510, "04"),  # reprogrammable keys V4
 | |
|     Response("12", 0x0600),  # friendly namme
 | |
|     Response("004142434445464748494A4B4C4D4E", 0x0610, "00"),
 | |
|     Response("0E4F50515253000000000000000000", 0x0610, "0E"),
 | |
|     Response("12", 0x0700),  # name and kind
 | |
|     Response("4142434445464748494A4B4C4D4E4F", 0x0710, "00"),
 | |
|     Response("505152530000000000000000000000", 0x0710, "0F"),
 | |
|     Response("00", 0x0720),
 | |
|     Response("12345678", 0x0800),  # battery status
 | |
| ]
 | |
| 
 | |
| r_mouse_1 = [  # a HID++ 1.0 mouse
 | |
|     Response(1.0, 0x0010),  # ping
 | |
| ]
 | |
| 
 | |
| r_mouse_2 = [  # a HID++ 2.0 mouse with few responses except for ping
 | |
|     Response(4.2, 0x0010),  # ping
 | |
| ]
 | |
| 
 | |
| r_mouse_3 = [  # a HID++ 2.0 mouse
 | |
|     Response(4.5, 0x0010),  # ping
 | |
|     Response("010001", 0x0000, "0001"),  # feature set at 0x01
 | |
|     Response("020002", 0x0000, "8060"),  # report rate at 0x02
 | |
|     Response("040001", 0x0000, "0003"),  # device information at 0x04
 | |
|     Response("050002", 0x0000, "0005"),  # device type and name at 0x05
 | |
|     Response("08", 0x0100),  # 8 features
 | |
|     Response("00010001", 0x0110, "01"),  # feature set at 0x01
 | |
|     Response("80600002", 0x0110, "02"),  # report rate at 0x02
 | |
|     Response("00030001", 0x0110, "04"),  # device information at 0x04
 | |
|     Response("00050002", 0x0110, "05"),  # device type and name at 0x05
 | |
|     Response("09", 0x0210),  # report rate - current rate
 | |
|     Response("03123456790008123456780000AA01", 0x0400),  # device information
 | |
|     Response("0141424302030100", 0x0410, "00"),  # firmware 0
 | |
|     Response("0241", 0x0410, "01"),  # firmware 1
 | |
|     Response("05", 0x0410, "02"),  # firmware 2
 | |
|     Response("12", 0x0500),  # name count - 18 characters
 | |
|     Response("414241424142414241424142414241", 0x0510, "00"),  # name - first 15 characters
 | |
|     Response("444544000000000000000000000000", 0x0510, "0F"),  # name - last 3 characters
 | |
| ]
 | |
| 
 | |
| 
 | |
| responses_key = [  # responses for Reprogrammable Keys V4 at 0x05
 | |
|     Response("08", 0x0500),  # Reprogrammable Keys V4 count
 | |
|     Response("00500038010001010400000000000000", 0x0510, "00"),  # left button
 | |
|     Response("00510039010001010400000000000000", 0x0510, "01"),  # right button
 | |
|     Response("0052003A310003070500000000000000", 0x0510, "02"),  # middle button
 | |
|     Response("0053003C710002030100000000000000", 0x0510, "03"),  # back button
 | |
|     Response("0056003E710002030100000000000000", 0x0510, "04"),  # forward button
 | |
|     Response("00C300A9310003070300000000000000", 0x0510, "05"),  # smart shift?
 | |
|     Response("00C4009D310003070500000000000000", 0x0510, "06"),  # ?
 | |
|     Response("00D700B4A00004000300000000000000", 0x0510, "07"),  # ?
 | |
|     Response("00500000000000000000000000000000", 0x0520, "0050"),  # left button
 | |
|     Response("00510000000000000000000000000000", 0x0520, "0051"),  # ...
 | |
|     Response("00520100500000000000000000000000", 0x0520, "0052"),
 | |
|     Response("00530500000000000000000000000000", 0x0520, "0053"),
 | |
|     Response("00561100000000000000000000000000", 0x0520, "0056"),
 | |
|     Response("00C30000000000000000000000000000", 0x0520, "00C3"),
 | |
|     Response("00C40000500000000000000000000000", 0x0520, "00C4"),
 | |
|     Response("00D70000510000000000000000000000", 0x0520, "00D7"),
 | |
|     Response("0041", 0x0400),  # flags
 | |
|     Response("0401", 0x0410),  # count
 | |
|     Response("0050", 0x0420, "00FF"),  # left button
 | |
|     Response("0051", 0x0420, "01FF"),  # right button
 | |
|     Response("0052", 0x0420, "02FF"),  # middle button
 | |
|     Response("0053", 0x0420, "03FF"),  # back button
 | |
|     Response("0050000100500000", 0x0430, "0050FF"),  # left button current
 | |
|     Response("0051000100500001", 0x0430, "0051FF"),  # right button current
 | |
|     Response("0052000100500001", 0x0430, "0052FF"),  # middle button current
 | |
|     Response("0053000100500001", 0x0430, "0053FF"),  # back button current
 | |
|     Response("0050FF01005000", 0x0440, "0050FF01005000"),  # left button write
 | |
|     Response("0051FF01005000", 0x0440, "0051FF01005000"),  # right button write
 | |
|     Response("0051FF01005100", 0x0440, "0051FF01005100"),  # right button set write
 | |
| ]
 | |
| 
 | |
| responses_remap = [  # responses for Persistent Remappable Actions at 0x04 and reprogrammable keys at 0x05
 | |
|     Response("0041", 0x0400),
 | |
|     Response("03", 0x0410),
 | |
|     Response("0301", 0x0410, "00"),
 | |
|     Response("0050", 0x0420, "00FF"),
 | |
|     Response("0050000200010001", 0x0430, "0050FF"),  # Left Button
 | |
|     Response("0051", 0x0420, "01FF"),
 | |
|     Response("0051000200010000", 0x0430, "0051FF"),  # Left Button
 | |
|     Response("0052", 0x0420, "02FF"),
 | |
|     Response("0052000100510000", 0x0430, "0052FF"),  # key DOWN
 | |
|     Response("050002", 0x0000, "1B04"),  # REPROGRAMMABLE_KEYS_V4
 | |
| ] + responses_key
 | |
| 
 | |
| responses_gestures = [  # the commented-out messages are not used by either the setting or other testing
 | |
|     Response("4203410141020400320480148C21A301", 0x0400, "0000"),  # items
 | |
|     Response("A302A11EA30A4105822C852DAD2AAD2B", 0x0400, "0008"),
 | |
|     Response("8F408F418F434204AF54912282558264", 0x0400, "0010"),
 | |
|     Response("01000000000000000000000000000000", 0x0400, "0018"),
 | |
|     Response("01000000000000000000000000000000", 0x0410, "000101"),  # enable
 | |
|     #    Response("02000000000000000000000000000000", 0x0410, "000102"),
 | |
|     #    Response("04000000000000000000000000000000", 0x0410, "000104"),
 | |
|     #    Response("08000000000000000000000000000000", 0x0410, "000108"),
 | |
|     Response("00000000000000000000000000000000", 0x0410, "000110"),
 | |
|     #    Response("20000000000000000000000000000000", 0x0410, "000120"),
 | |
|     #    Response("40000000000000000000000000000000", 0x0410, "000140"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0410, "000180"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0410, "010101"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0410, "010102"),
 | |
|     #    Response("04000000000000000000000000000000", 0x0410, "010104"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0410, "010108"),
 | |
|     Response("6F000000000000000000000000000000", 0x0410, "0001FF"),
 | |
|     Response("04000000000000000000000000000000", 0x0410, "01010F"),
 | |
|     Response("00000000000000000000000000000000", 0x0430, "000101"),  # divert
 | |
|     #    Response("00000000000000000000000000000000", 0x0430, "000102"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0430, "000104"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0430, "000108"),
 | |
|     Response("00000000000000000000000000000000", 0x0430, "000110"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0430, "000120"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0430, "000140"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0430, "000180"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0430, "010101"),
 | |
|     #    Response("00000000000000000000000000000000", 0x0430, "010102"),
 | |
|     Response("00000000000000000000000000000000", 0x0430, "0001FF"),
 | |
|     Response("00000000000000000000000000000000", 0x0430, "010103"),
 | |
|     Response("08000000000000000000000000000000", 0x0450, "01FF"),
 | |
|     Response("08000000000000000000000000000000", 0x0450, "02FF"),
 | |
|     Response("08000000000000000000000000000000", 0x0450, "03FF"),
 | |
|     Response("00040000000000000000000000000000", 0x0450, "04FF"),
 | |
|     Response("5C020000000000000000000000000000", 0x0450, "05FF"),
 | |
|     Response("01000000000000000000000000000000", 0x0460, "00FF"),
 | |
|     Response("01000000000000000000000000000000", 0x0470, "00FF"),
 | |
|     Response("01", 0x0420, "00010101"),  # set index 1
 | |
|     Response("00", 0x0420, "00010100"),  # unset index 1
 | |
|     Response("01", 0x0420, "00011010"),  # set index 4
 | |
|     Response("00", 0x0420, "00011000"),  # unset index 4
 | |
|     Response("01", 0x0440, "00010101"),  # divert index 1
 | |
|     Response("00", 0x0440, "00010100"),  # undivert index 1
 | |
|     Response("000080FF", 0x0480, "000080FF"),  # write param 0
 | |
|     Response("000180FF", 0x0480, "000180FF"),  # write param 0
 | |
| ]
 | |
| 
 | |
| zone_responses_1 = [  # responses for COLOR LED EFFECTS
 | |
|     Response("00000102", 0x0710, "00FF00"),
 | |
|     Response("0000000300040005", 0x0720, "000000"),
 | |
|     Response("0001000B00080009", 0x0720, "000100"),
 | |
| ]
 | |
| zone_responses_2 = [  # responses for RGB EFFECTS
 | |
|     Response("0000000102", 0x0700, "00FF00"),
 | |
|     Response("0000000300040005", 0x0700, "000000"),
 | |
|     Response("0001000200080009", 0x0700, "000100"),
 | |
| ]
 | |
| effects_responses_1 = [Response("0100000001", 0x0700)] + zone_responses_1
 | |
| effects_responses_2 = [Response("FFFF0100000001", 0x0700, "FFFF00")] + zone_responses_2
 | |
| 
 | |
| responses_profiles = [  # OnboardProfile in RAM
 | |
|     Response("0104010101020100FE0200", 0x0900),
 | |
|     Response("000101FF", 0x0950, "00000000"),
 | |
|     Response("FFFFFFFF", 0x0950, "00000004"),
 | |
|     Response("01010290018003000700140028FFFFFF", 0x0950, "00010000"),
 | |
|     Response("FFFF0000000000000000000000000000", 0x0950, "00010010"),
 | |
|     Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "00010020"),
 | |
|     Response("900aFF00800204548000FFFF900aFF00", 0x0950, "00010030"),
 | |
|     Response("800204548000FFFF900aFF0080020454", 0x0950, "00010040"),
 | |
|     Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "00010050"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010060"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010070"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010080"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010090"),
 | |
|     Response("54004500370000000000000000000000", 0x0950, "000100A0"),
 | |
|     Response("00000000000000000000000000000000", 0x0950, "000100B0"),
 | |
|     Response("00000000000000000000000000000000", 0x0950, "000100C0"),
 | |
|     Response("0A01020300500407000000FFFFFFFFFF", 0x0950, "000100D0"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "000100E0"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0950, "000100EE"),
 | |
| ]
 | |
| responses_profiles_rom = [  # OnboardProfile in ROM
 | |
|     Response("0104010101020100FE0200", 0x0900),
 | |
|     Response("00000000", 0x0950, "00000000"),
 | |
|     Response("010101FF", 0x0950, "01000000"),
 | |
|     Response("FFFFFFFF", 0x0950, "01000004"),
 | |
|     Response("01010290018003000700140028FFFFFF", 0x0950, "01010000"),
 | |
|     Response("FFFF0000000000000000000000000000", 0x0950, "01010010"),
 | |
|     Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010020"),
 | |
|     Response("900aFF00800204548000FFFF900aFF00", 0x0950, "01010030"),
 | |
|     Response("800204548000FFFF900aFF0080020454", 0x0950, "01010040"),
 | |
|     Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010050"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010060"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010070"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010080"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010090"),
 | |
|     Response("54004500370000000000000000000000", 0x0950, "010100A0"),
 | |
|     Response("00000000000000000000000000000000", 0x0950, "010100B0"),
 | |
|     Response("00000000000000000000000000000000", 0x0950, "010100C0"),
 | |
|     Response("0A01020300500407000000FFFFFFFFFF", 0x0950, "010100D0"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "010100E0"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0950, "010100EE"),
 | |
| ]
 | |
| responses_profiles_rom_2 = [  # OnboardProfile in ROM
 | |
|     Response("0104010101020100FE0200", 0x0900),
 | |
|     Response("FFFFFFFF", 0x0950, "00000000"),
 | |
|     Response("010101FF", 0x0950, "01000000"),
 | |
|     Response("FFFFFFFF", 0x0950, "01000004"),
 | |
|     Response("01010290018003000700140028FFFFFF", 0x0950, "01010000"),
 | |
|     Response("FFFF0000000000000000000000000000", 0x0950, "01010010"),
 | |
|     Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010020"),
 | |
|     Response("900aFF00800204548000FFFF900aFF00", 0x0950, "01010030"),
 | |
|     Response("800204548000FFFF900aFF0080020454", 0x0950, "01010040"),
 | |
|     Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010050"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010060"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010070"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010080"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010090"),
 | |
|     Response("54004500370000000000000000000000", 0x0950, "010100A0"),
 | |
|     Response("00000000000000000000000000000000", 0x0950, "010100B0"),
 | |
|     Response("00000000000000000000000000000000", 0x0950, "010100C0"),
 | |
|     Response("0A01020300500407000000FFFFFFFFFF", 0x0950, "010100D0"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "010100E0"),
 | |
|     Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0950, "010100EE"),
 | |
| ]
 | |
| 
 | |
| complex_responses_1 = [  # COLOR_LED_EFFECTS
 | |
|     Response(4.2, 0x0010),  # ping
 | |
|     Response("010001", 0x0000, "0001"),  # FEATURE SET at x01
 | |
|     Response("020001", 0x0000, "0020"),  # CONFIG_CHANGE at x02
 | |
|     Response("0A", 0x0100),  # 10 features
 | |
|     Response("070001", 0x0000, "8070"),  # COLOR_LED_EFFECTS at 0x07
 | |
|     *effects_responses_1,
 | |
| ]
 | |
| 
 | |
| complex_responses_2 = [  # RGB_EFFECTS + reprogrammable keys + persistent actions
 | |
|     Response(4.2, 0x0010),  # ping
 | |
|     Response("010001", 0x0000, "0001"),  # FEATURE SET at x01
 | |
|     Response("020001", 0x0000, "0020"),  # CONFIG_CHANGE at x02
 | |
|     Response("0A", 0x0100),  # 10 features
 | |
|     Response("070001", 0x0000, "8071"),  # RGB_EFFECTS at 0x07
 | |
|     *effects_responses_2,
 | |
|     Response("040001", 0x0000, "1C00"),  # Persistent Remappable Actions at 0x04
 | |
|     *responses_remap,
 | |
|     Response("080001", 0x0000, "6501"),  # Gestures at 0x08
 | |
|     *adjust_responses_index(8, responses_gestures),
 | |
|     Response("060003", 0x0000, "1982"),  # Backlight 2 at 0x06
 | |
|     Response("010118000001020003000400", 0x0600),
 | |
|     Response("090003", 0x0000, "8100"),  # Onboard Profiles at 0x09
 | |
|     *responses_profiles,
 | |
| ]
 | |
| 
 | |
| responses_speedchange = [
 | |
|     Response("0100", 0x0400),
 | |
|     Response("010001", 0x0000, "0001"),  # FEATURE SET at x01
 | |
|     Response("0A", 0x0100),  # 10 features
 | |
|     Response("0120", 0x0410, "0120"),
 | |
|     Response("050001", 0x0000, "1B04"),  # REPROG_CONTROLS_V4
 | |
|     Response("01", 0x0500),
 | |
|     Response("00ED009D310003070500000000000000", 0x0510, "00"),  # DPI Change
 | |
|     Response("00ED0000000000000000000000000000", 0x0520, "00ED"),  # DPI Change current
 | |
|     Response("060000", 0x0000, "2205"),  # POINTER_SPEED
 | |
| ]
 | |
| 
 | |
| 
 | |
| # A fake device that uses provided data (responses) to respond to HID++ commands.
 | |
| # Some methods from the real device are used to set up data structures needed for settings
 | |
| @dataclass
 | |
| class Device:
 | |
|     name: str = "TESTD"
 | |
|     online: bool = True
 | |
|     protocol: float = 2.0
 | |
|     responses: Any = field(default_factory=list)
 | |
|     codename: str = "TESTC"
 | |
|     feature: Optional[int] = None
 | |
|     offset: Optional[int] = 4
 | |
|     version: Optional[int] = 0
 | |
|     wpid: Optional[str] = "0000"
 | |
|     setting_callback: Any = None
 | |
|     sliding = profiles = _backlight = _keys = _remap_keys = _led_effects = _gestures = None
 | |
|     _gestures_lock = threading.Lock()
 | |
| 
 | |
|     read_register = device.Device.read_register
 | |
|     write_register = device.Device.write_register
 | |
|     backlight = device.Device.backlight
 | |
|     keys = device.Device.keys
 | |
|     remap_keys = device.Device.remap_keys
 | |
|     led_effects = device.Device.led_effects
 | |
|     gestures = device.Device.gestures
 | |
|     __hash__ = device.Device.__hash__
 | |
|     feature_request = device.Device.feature_request
 | |
| 
 | |
|     def __post_init__(self):
 | |
|         self._name = self.name
 | |
|         self._protocol = self.protocol
 | |
|         self.persister = configuration._DeviceEntry()
 | |
|         self.features = hidpp20.FeaturesArray(self)
 | |
|         self.settings = []
 | |
|         if self.feature is not None:
 | |
|             self.features = hidpp20.FeaturesArray(self)
 | |
|             self.responses = [Response("010001", 0x0000, "0001"), Response("20", 0x0100)] + self.responses
 | |
|             self.responses.append(Response(f"{self.offset:0>2X}00{self.version:0>2X}", 0x0000, f"{self.feature:0>4X}"))
 | |
|         if self.setting_callback is None:
 | |
|             self.setting_callback = lambda x, y, z: None
 | |
|         self.add_notification_handler = lambda x, y: None
 | |
| 
 | |
|     def request(self, id, *params, no_reply=False, long_message=False, protocol=2.0):
 | |
|         params = b"".join(pack("B", p) if isinstance(p, int) else p for p in params)
 | |
|         print("REQUEST ", self._name, hex(id), params.hex().upper())
 | |
|         for r in self.responses:
 | |
|             if id == r.id and params == bytes.fromhex(r.params):
 | |
|                 print("RESPONSE", self._name, hex(r.id), r.params, r.response)
 | |
|                 return bytes.fromhex(r.response) if isinstance(r.response, str) else r.response
 | |
|         print("RESPONSE", self._name, None)
 | |
| 
 | |
|     def ping(self, handle=None, devnumber=None, long_message=False):
 | |
|         print("PING", self._protocol)
 | |
|         return self._protocol
 | |
| 
 | |
| 
 | |
| def match_requests(number, responses, call_args_list):
 | |
|     for i in range(0 - number, 0):
 | |
|         param = b"".join(pack("B", p) if isinstance(p, int) else p for p in call_args_list[i][0][1:]).hex().upper()
 | |
|         print("MATCH", i, hex(call_args_list[i][0][0]), param, hex(responses[i].id), responses[i].params)
 | |
|         assert call_args_list[i][0][0] == responses[i].id
 | |
|         assert param == responses[i].params
 |