From 784e442fafa6cad2cbe311397dea347ea2f90cb0 Mon Sep 17 00:00:00 2001 From: sephiroth99 Date: Tue, 19 Oct 2021 02:01:03 -0400 Subject: [PATCH 1/8] handlers: separate range processing in its own function The 'process_value' function of the 'range' handler is reused by 'multidpi_range'. Separate the actual processing in a different function. This will make it possible in future commits to change the return of 'process_value' for the 'range' handler. --- rivalcfg/handlers/multidpi_range.py | 6 +++--- rivalcfg/handlers/range.py | 22 +++++++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/rivalcfg/handlers/multidpi_range.py b/rivalcfg/handlers/multidpi_range.py index 3911a0f5..847983cf 100644 --- a/rivalcfg/handlers/multidpi_range.py +++ b/rivalcfg/handlers/multidpi_range.py @@ -80,7 +80,7 @@ import argparse from ..helpers import merge_bytes, uint_to_little_endian_bytearray -from .range import process_value as range_process_value +from .range import process_range def process_value(setting_info, value, selected_preset=None): @@ -154,8 +154,8 @@ def process_value(setting_info, value, selected_preset=None): output_values = [] for dpi in dpis: - value = range_process_value(setting_info, dpi) - value = uint_to_little_endian_bytearray(value[0], dpi_length) + value = process_range(setting_info, dpi) + value = uint_to_little_endian_bytearray(value, dpi_length) output_values = merge_bytes(output_values, value) # Count diff --git a/rivalcfg/handlers/range.py b/rivalcfg/handlers/range.py index 63edc72c..3d2d8d20 100644 --- a/rivalcfg/handlers/range.py +++ b/rivalcfg/handlers/range.py @@ -128,14 +128,14 @@ def custom_range(start, stop, step): i += step -def process_value(setting_info, value): - """Called by the :class:`rivalcfg.mouse.Mouse` class when processing a - "range" type setting. +def process_range(setting_info, value): + """Called by the "range" functions to process 'value' with the specified + range settings in 'setting_info'. :param dict setting_info: The information dict of the setting from the device profile. :param value: The input value. - :rtype: list[int] + :rtype: int """ input_range = list( range( @@ -161,7 +161,19 @@ def process_value(setting_info, value): setting_info["input_range"][2], int(value), ) - return [output_range[input_range.index(matched_value)]] + return output_range[input_range.index(matched_value)] + + +def process_value(setting_info, value): + """Called by the :class:`rivalcfg.mouse.Mouse` class when processing a + "range" type setting. + + :param dict setting_info: The information dict of the setting from the + device profile. + :param value: The input value. + :rtype: list[int] + """ + return [process_range(setting_info, value)] def add_cli_option(cli_parser, setting_name, setting_info): From e810469bdaf0b28f3c0078390956fd0c19b12009 Mon Sep 17 00:00:00 2001 From: sephiroth99 Date: Tue, 19 Oct 2021 02:15:06 -0400 Subject: [PATCH 2/8] handlers: range: Support multi byte output Add support for outputting a value on multiple bytes. The new device option is called 'range_length_byte'. --- rivalcfg/handlers/range.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/rivalcfg/handlers/range.py b/rivalcfg/handlers/range.py index 3d2d8d20..108210d8 100644 --- a/rivalcfg/handlers/range.py +++ b/rivalcfg/handlers/range.py @@ -67,6 +67,9 @@ """ +from ..helpers import uint_to_little_endian_bytearray + + def matches_value_in_range(range_start, range_stop, range_step, value): """Helper function that matches the value with the nearest value in the given range. @@ -173,7 +176,12 @@ def process_value(setting_info, value): :param value: The input value. :rtype: list[int] """ - return [process_range(setting_info, value)] + range_length = 1 + if "range_length_byte" in setting_info: + range_length = setting_info["range_length_byte"] + return uint_to_little_endian_bytearray( + process_range(setting_info, value), range_length + ) def add_cli_option(cli_parser, setting_name, setting_info): From 05190df038c5bcd86aa540b2384d184f81f78f1f Mon Sep 17 00:00:00 2001 From: sephiroth99 Date: Mon, 18 Oct 2021 21:15:29 -0400 Subject: [PATCH 3/8] devices: prime: add initial support --- rivalcfg/devices/__init__.py | 1 + rivalcfg/devices/prime.py | 89 ++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 rivalcfg/devices/prime.py diff --git a/rivalcfg/devices/__init__.py b/rivalcfg/devices/__init__.py index c8c4e48d..b48197e9 100644 --- a/rivalcfg/devices/__init__.py +++ b/rivalcfg/devices/__init__.py @@ -148,6 +148,7 @@ from . import aerox3 # noqa: F401 from . import kanav2 # noqa: F401 from . import kinzuv2 # noqa: F401 +from . import prime # noqa: F401 from . import rival3 # noqa: F401 from . import rival95 # noqa: F401 from . import rival100 # noqa: F401 diff --git a/rivalcfg/devices/prime.py b/rivalcfg/devices/prime.py new file mode 100644 index 00000000..5532faf5 --- /dev/null +++ b/rivalcfg/devices/prime.py @@ -0,0 +1,89 @@ +from .. import usbhid + + +profile = { + "name": "SteelSeries Prime", + "models": [ + { + "name": "SteelSeries Prime", + "vendor_id": 0x1038, + "product_id": 0x182E, + "endpoint": 0, + }, + ], + "settings": { + "sensitivity": { + "label": "Sensitivity presets", + "description": "Set sensitivity preset (DPI)", + "cli": ["-s", "--sensitivity"], + "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, + "command": [0x61], + "value_type": "multidpi_range", + "input_range": [50, 18000, 50], + "output_range": [1, 0x0168, 1], + "dpi_length_byte": 2, + "count_mode": "number", + "first_preset": 0, + "max_preset_count": 5, + "default": "400, 800, 1200, 2400, 3200", + }, + "polling_rate": { + "label": "Polling rate", + "description": "Set polling rate (Hz)", + "cli": ["-p", "--polling-rate"], + "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, + "command": [0x5D], + "value_type": "choice", + "choices": { + 125: 0x04, + 250: 0x03, + 500: 0x02, + 1000: 0x01, + }, + "default": 1000, + }, + "color": { + "label": "Wheel LED color", + "description": "Set the color of the wheel LED", + "cli": ["-c", "--color"], + "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, + "command": [0x62, 0x01], + "command_suffix": [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0xFF, + ], + "value_type": "rgbcolor", + "default": "#FF5200", + }, + "wheel_brightness": { + "label": "Wheel LED brightness", + "description": "Set the brightness of the wheel LED", + "cli": ["-l", "--led-brightness"], + "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, + "command": [0x5F], + "value_type": "range", + "input_range": [0, 256, 1], + "output_range": [0, 256, 1], + "range_length_byte": 2, + "default": 256, + }, + }, + "save_command": { + "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, + "command": [0x59], + }, +} From 2bd69c6514b9a47863f4669f59f6a0d6a9efed2f Mon Sep 17 00:00:00 2001 From: sephiroth99 Date: Tue, 19 Oct 2021 23:57:28 -0400 Subject: [PATCH 4/8] test: Add range tests for multi byte output --- test/handlers/test_range.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/handlers/test_range.py b/test/handlers/test_range.py index 92ff7359..0b5747e6 100644 --- a/test/handlers/test_range.py +++ b/test/handlers/test_range.py @@ -14,6 +14,15 @@ def setting_info(self): "output_range": [2, 40, 2], } + @pytest.fixture + def setting_info2(self): + return { + "value_type": "range", + "input_range": [1, 20, 1], + "output_range": [1000, 40000, 2000], + "range_length_byte": 2, + } + @pytest.mark.parametrize( "input_,expected_output", [ @@ -28,6 +37,18 @@ def setting_info(self): def test_range_values(self, setting_info, input_, expected_output): assert range_.process_value(setting_info, input_) == [expected_output] + @pytest.mark.parametrize( + "input_,expected_output", + [ + (1, [0xE8, 0x03]), + (2, [0xB8, 0x0B]), + (20, [0x58, 0x98]), + (14, [0x78, 0x69]), + ], + ) + def test_range_values2(self, setting_info2, input_, expected_output): + assert range_.process_value(setting_info2, input_) == expected_output + class TestAddCliOption(object): @pytest.fixture From 240dbedfed8a7e549ab8d072922d0c4553084ae6 Mon Sep 17 00:00:00 2001 From: sephiroth99 Date: Wed, 20 Oct 2021 00:56:19 -0400 Subject: [PATCH 5/8] test: Add tests for Prime mice --- test/devices/test_prime.py | 87 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 test/devices/test_prime.py diff --git a/test/devices/test_prime.py b/test/devices/test_prime.py new file mode 100644 index 00000000..54fbf192 --- /dev/null +++ b/test/devices/test_prime.py @@ -0,0 +1,87 @@ +import pytest + +from rivalcfg import usbhid +from rivalcfg import mouse +from rivalcfg.devices import prime +from rivalcfg import mouse_settings + + +class TestDevice(object): + @pytest.fixture + def mouse(self): + settings = mouse_settings.FakeMouseSettings( + 0x1038, + 0xBAAD, + prime.profile, + ) + return mouse.Mouse( + usbhid.FakeDevice(), + prime.profile, + settings, + ) + + @pytest.mark.parametrize( + "value,expected_hid_report", + [ + (100, b"\x02\x00\x61\x01\x00\x02\x00"), + ("100", b"\x02\x00\x61\x01\x00\x02\x00"), + ("500,2500", b"\x02\x00\x61\x02\x00\x0A\x00\x32\x00"), + ( + "500,2500,11050,18000", + b"\x02\x00\x61\x04\x00\x0A\x00\x32\x00\xDD\x00\x68\x01", + ), + ], + ) + def test_set_sensitivity(self, mouse, value, expected_hid_report): + mouse.set_sensitivity(value) + mouse._hid_device.bytes.seek(0) + hid_report = mouse._hid_device.bytes.read() + assert hid_report == expected_hid_report + + @pytest.mark.parametrize( + "value,expected_hid_report", + [ + (125, b"\x02\x00\x5D\x04"), + (250, b"\x02\x00\x5D\x03"), + (500, b"\x02\x00\x5D\x02"), + (1000, b"\x02\x00\x5D\x01"), + ], + ) + def test_set_polling_rate(self, mouse, value, expected_hid_report): + mouse.set_polling_rate(value) + mouse._hid_device.bytes.seek(0) + hid_report = mouse._hid_device.bytes.read() + assert hid_report == expected_hid_report + + @pytest.mark.parametrize( + "value,expected_hid_report", + [ + ( + "#ABCDEF", + b"\x02\x00\x62\x01\xAB\xCD\xEF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF", + ), + ( + "red", + b"\x02\x00\x62\x01\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF", + ), + ], + ) + def test_set_color(self, mouse, value, expected_hid_report): + mouse.set_color(value) + mouse._hid_device.bytes.seek(0) + hid_report = mouse._hid_device.bytes.read() + assert hid_report == expected_hid_report + + @pytest.mark.parametrize( + "value,expected_hid_report", + [ + (0, b"\x02\x00\x5F\x00\x00"), + (256, b"\x02\x00\x5F\x00\x01"), + (111, b"\x02\x00\x5F\x6F\x00"), + ], + ) + def test_set_wheel_brightness(self, mouse, value, expected_hid_report): + mouse.set_wheel_brightness(value) + mouse._hid_device.bytes.seek(0) + hid_report = mouse._hid_device.bytes.read() + assert hid_report == expected_hid_report From 587bdb7c59684440ef6b61dd95fae710196bc4a5 Mon Sep 17 00:00:00 2001 From: sephiroth99 Date: Thu, 18 Nov 2021 22:26:19 -0500 Subject: [PATCH 6/8] doc: devices: add Prime documentation --- doc/devices/index.rst | 1 + doc/devices/prime.rst | 56 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 doc/devices/prime.rst diff --git a/doc/devices/index.rst b/doc/devices/index.rst index 48fe89c2..f3af8f35 100644 --- a/doc/devices/index.rst +++ b/doc/devices/index.rst @@ -10,6 +10,7 @@ Supported Devices ./aerox3.rst ./kanav2.rst ./kinzuv2.rst + ./prime.rst ./rival3.rst ./rival95.rst ./rival100.rst diff --git a/doc/devices/prime.rst b/doc/devices/prime.rst new file mode 100644 index 00000000..eebe747c --- /dev/null +++ b/doc/devices/prime.rst @@ -0,0 +1,56 @@ +SteelSeries Prime +=================== + + +Supported Models +---------------- + +.. rivalcfg_device_family:: prime + + +Command-Line Usage +------------------ + +.. rivalcfg_device_cli:: prime + + +Sensitivity (DPI) +----------------- + +This mouse supports up to 5 sensitivity presets. You can define them like this: + +:: + + rivalcfg --sensitivity 800 # one preset + rivalcfg --sensitivity 800,1600 # two presets + +You can switch preset using the button under the mouse wheel. + +.. NOTE:: + + When you set the sensitivity through the CLI, the selected preset always + back to the first one. + + +.. NOTE:: From Python API, you can pass an ``int``, a ``tuple`` or a ``list`` + as parameter. You are also able to change the currently selected preset:: + + mouse.sensitivity(800) + mouse.sensitivity("800, 1600") + mouse.sensitivity([800, 1600]) + # select the second preset (1600 dpi) + mouse.sensitivity([800, 1600, 2000, 4000], selected_preset=2) + + +Colors +------ + +This mouse supports colors. Various formats are supported. + +.. include:: ./_colors.rst + + +Python API +---------- + +TODO From a01c3be74af9cc56db35c8c9b02de06ac2af6d15 Mon Sep 17 00:00:00 2001 From: sephiroth99 Date: Sat, 27 Nov 2021 01:43:24 -0500 Subject: [PATCH 7/8] devices: prime: update name of brightness section --- rivalcfg/devices/prime.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rivalcfg/devices/prime.py b/rivalcfg/devices/prime.py index 5532faf5..8770554b 100644 --- a/rivalcfg/devices/prime.py +++ b/rivalcfg/devices/prime.py @@ -69,7 +69,7 @@ "value_type": "rgbcolor", "default": "#FF5200", }, - "wheel_brightness": { + "led_brightness": { "label": "Wheel LED brightness", "description": "Set the brightness of the wheel LED", "cli": ["-l", "--led-brightness"], From dffa7e3da96081d9cc8067774d197513c6106960 Mon Sep 17 00:00:00 2001 From: sephiroth99 Date: Sat, 27 Nov 2021 01:43:52 -0500 Subject: [PATCH 8/8] tests: prime: use new name for brightness function --- test/devices/test_prime.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/devices/test_prime.py b/test/devices/test_prime.py index 54fbf192..5deecaa3 100644 --- a/test/devices/test_prime.py +++ b/test/devices/test_prime.py @@ -80,8 +80,8 @@ def test_set_color(self, mouse, value, expected_hid_report): (111, b"\x02\x00\x5F\x6F\x00"), ], ) - def test_set_wheel_brightness(self, mouse, value, expected_hid_report): - mouse.set_wheel_brightness(value) + def test_set_led_brightness(self, mouse, value, expected_hid_report): + mouse.set_led_brightness(value) mouse._hid_device.bytes.seek(0) hid_report = mouse._hid_device.bytes.read() assert hid_report == expected_hid_report