From ea5390dcc25fc7049aa146bb736d0c5d35aa281f Mon Sep 17 00:00:00 2001 From: Zebreus Date: Mon, 10 Mar 2025 18:19:31 +0100 Subject: [PATCH 1/3] Add basic support for aerox 9 buttons --- rivalcfg/devices/aerox9_wireless_wired.py | 80 +++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/rivalcfg/devices/aerox9_wireless_wired.py b/rivalcfg/devices/aerox9_wireless_wired.py index bf0ea70e..1484a923 100644 --- a/rivalcfg/devices/aerox9_wireless_wired.py +++ b/rivalcfg/devices/aerox9_wireless_wired.py @@ -134,6 +134,86 @@ }, "default": "rainbow", }, + "buttons_mapping1": { + "label": "Buttons mapping 1", + "description": "Set the mapping of the normal mouse buttons and scrollwheel left/right", + "cli": ["--buttons1"], + "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, + "command": [0x2A, 0x00], + "value_type": "buttons", + # fmt: off + "buttons": { + "Button1": {"id": 0x01, "offset": 0, "default": "button1"}, + "Button2": {"id": 0x02, "offset": 5, "default": "button2"}, + "Button3": {"id": 0x03, "offset": 10, "default": "button3"}, + "Button4": {"id": 0x04, "offset": 15, "default": "button4"}, # Wheel Left + "Button5": {"id": 0x05, "offset": 20, "default": "button5"}, # Wheel Right + "Button6": {"id": 0x06, "offset": 25, "default": "dpi"}, + }, + "button_field_length": 5, + "button_disable": 0x00, + "button_keyboard": 0x51, + "button_multimedia": 0x61, + "button_dpi_switch": 0x30, + "button_scroll_up": None, + "button_scroll_down": None, + # fmt: on + "default": "buttons(button1=button1; button2=button2; button3=button3; button4=button4; button5=button5; button6=dpi; layout=qwerty)", + }, + "buttons_mapping_2": { + "label": "Buttons mapping 2", + "description": "Set the mapping of the first half of the numpad", + "cli": ["--buttons2"], + "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, + "command": [0x2A, 0x01], + "value_type": "buttons", + # fmt: off + "buttons": { + "Numpad3": {"id": 0x01, "offset": 0, "default": "3"}, + "Numpad6": {"id": 0x02, "offset": 5, "default": "6"}, # dpi? + "Numpad9": {"id": 0x03, "offset": 10, "default": "9"}, + "Numpad12": {"id": 0x04, "offset": 15, "default": "="}, # numpad7 + "Numpad2": {"id": 0x05, "offset": 20, "default": "2"}, + "Numpad5": {"id": 0x06, "offset": 25, "default": "5"}, + }, + "button_field_length": 5, + "button_disable": 0x00, + "button_keyboard": 0x51, + "button_multimedia": 0x61, + "button_dpi_switch": 0x30, + "button_scroll_up": None, + "button_scroll_down": None, + # fmt: on + "default": "buttons(numpad3=3; numpad6=6; numpad9=9; numpad12=equal; numpad2=2; numpad5=5; layout=qwerty)", + }, + "buttons_mapping_3": { + "label": "Buttons mapping 3", + "description": "Set the mapping of the scrollwheel and the second half of the numpad", + "cli": ["--buttons3"], + "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, + "command": [0x2A, 0x02], + "value_type": "buttons", + # fmt: off + "buttons": { + "Numpad8": {"id": 0x01, "offset": 0, "default": "8"}, + "Numpad11": {"id": 0x02, "offset": 5, "default": "-"}, + "Numpad1": {"id": 0x03, "offset": 10, "default": "1"}, + "Numpad4": {"id": 0x04, "offset": 15, "default": "4"}, + "Numpad7": {"id": 0x05, "offset": 20, "default": "7"}, + "Numpad10": {"id": 0x06, "offset": 25, "default": "0"}, + "ScrollUp": {"id": 0x31, "offset": 30, "default": "scrollup"}, + "ScrollDown": {"id": 0x32, "offset": 35, "default": "scrolldown"}, + }, + "button_field_length": 5, + "button_disable": 0x00, + "button_keyboard": 0x51, + "button_multimedia": 0x61, + "button_dpi_switch": 0x30, + "button_scroll_up": None, + "button_scroll_down": None, + # fmt: on + "default": "buttons(numpad8=8; numpad11=-; numpad1=1; numpad4=4; numpad7=7; numpad10=0; scrollup=scrollup; scrolldown=scrolldown; layout=qwerty)", + }, }, "battery_level": { "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, From 5bc980029f22611efa2986516072e9c2a304f66d Mon Sep 17 00:00:00 2001 From: Zebreus Date: Mon, 10 Mar 2025 19:46:32 +0100 Subject: [PATCH 2/3] Add support for sending multiple packets in one cli command --- rivalcfg/devices/aerox9_wireless_wired.py | 81 ++++++----------------- rivalcfg/handlers/buttons/buttons.py | 10 +++ rivalcfg/mouse.py | 34 +++++----- 3 files changed, 50 insertions(+), 75 deletions(-) diff --git a/rivalcfg/devices/aerox9_wireless_wired.py b/rivalcfg/devices/aerox9_wireless_wired.py index 1484a923..898b91f1 100644 --- a/rivalcfg/devices/aerox9_wireless_wired.py +++ b/rivalcfg/devices/aerox9_wireless_wired.py @@ -134,12 +134,13 @@ }, "default": "rainbow", }, - "buttons_mapping1": { - "label": "Buttons mapping 1", - "description": "Set the mapping of the normal mouse buttons and scrollwheel left/right", - "cli": ["--buttons1"], + "buttons_mapping": { + "label": "Buttons mapping", + "description": "Set the mapping of the buttons", + "cli": ["-b", "--buttons"], "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, - "command": [0x2A, 0x00], + "command": [0x2A], + "split_packet_at": [30, 60], "value_type": "buttons", # fmt: off "buttons": { @@ -149,6 +150,20 @@ "Button4": {"id": 0x04, "offset": 15, "default": "button4"}, # Wheel Left "Button5": {"id": 0x05, "offset": 20, "default": "button5"}, # Wheel Right "Button6": {"id": 0x06, "offset": 25, "default": "dpi"}, + "Numpad3": {"id": 0x00, "offset": 30, "default": "3"}, + "Numpad6": {"id": 0x00, "offset": 35, "default": "6"}, # dpi? + "Numpad9": {"id": 0x00, "offset": 40, "default": "9"}, + "Numpad12": {"id": 0x00, "offset": 45, "default": "="}, # numpad7 + "Numpad2": {"id": 0x00, "offset": 50, "default": "2"}, + "Numpad5": {"id": 0x00, "offset": 55, "default": "5"}, + "Numpad8": {"id": 0x00, "offset": 60, "default": "8"}, + "Numpad11": {"id": 0x00, "offset": 65, "default": "-"}, + "Numpad1": {"id": 0x00, "offset": 70, "default": "1"}, + "Numpad4": {"id": 0x00, "offset": 75, "default": "4"}, + "Numpad7": {"id": 0x00, "offset": 80, "default": "7"}, + "Numpad10": {"id": 0x00, "offset": 85, "default": "0"}, + "ScrollUp": {"id": 0x31, "offset": 90, "default": "scrollup"}, + "ScrollDown": {"id": 0x32, "offset": 95, "default": "scrolldown"}, }, "button_field_length": 5, "button_disable": 0x00, @@ -158,61 +173,7 @@ "button_scroll_up": None, "button_scroll_down": None, # fmt: on - "default": "buttons(button1=button1; button2=button2; button3=button3; button4=button4; button5=button5; button6=dpi; layout=qwerty)", - }, - "buttons_mapping_2": { - "label": "Buttons mapping 2", - "description": "Set the mapping of the first half of the numpad", - "cli": ["--buttons2"], - "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, - "command": [0x2A, 0x01], - "value_type": "buttons", - # fmt: off - "buttons": { - "Numpad3": {"id": 0x01, "offset": 0, "default": "3"}, - "Numpad6": {"id": 0x02, "offset": 5, "default": "6"}, # dpi? - "Numpad9": {"id": 0x03, "offset": 10, "default": "9"}, - "Numpad12": {"id": 0x04, "offset": 15, "default": "="}, # numpad7 - "Numpad2": {"id": 0x05, "offset": 20, "default": "2"}, - "Numpad5": {"id": 0x06, "offset": 25, "default": "5"}, - }, - "button_field_length": 5, - "button_disable": 0x00, - "button_keyboard": 0x51, - "button_multimedia": 0x61, - "button_dpi_switch": 0x30, - "button_scroll_up": None, - "button_scroll_down": None, - # fmt: on - "default": "buttons(numpad3=3; numpad6=6; numpad9=9; numpad12=equal; numpad2=2; numpad5=5; layout=qwerty)", - }, - "buttons_mapping_3": { - "label": "Buttons mapping 3", - "description": "Set the mapping of the scrollwheel and the second half of the numpad", - "cli": ["--buttons3"], - "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, - "command": [0x2A, 0x02], - "value_type": "buttons", - # fmt: off - "buttons": { - "Numpad8": {"id": 0x01, "offset": 0, "default": "8"}, - "Numpad11": {"id": 0x02, "offset": 5, "default": "-"}, - "Numpad1": {"id": 0x03, "offset": 10, "default": "1"}, - "Numpad4": {"id": 0x04, "offset": 15, "default": "4"}, - "Numpad7": {"id": 0x05, "offset": 20, "default": "7"}, - "Numpad10": {"id": 0x06, "offset": 25, "default": "0"}, - "ScrollUp": {"id": 0x31, "offset": 30, "default": "scrollup"}, - "ScrollDown": {"id": 0x32, "offset": 35, "default": "scrolldown"}, - }, - "button_field_length": 5, - "button_disable": 0x00, - "button_keyboard": 0x51, - "button_multimedia": 0x61, - "button_dpi_switch": 0x30, - "button_scroll_up": None, - "button_scroll_down": None, - # fmt: on - "default": "buttons(numpad8=8; numpad11=-; numpad1=1; numpad4=4; numpad7=7; numpad10=0; scrollup=scrollup; scrolldown=scrolldown; layout=qwerty)", + "default": "buttons(button1=button1; button2=button2; button3=button3; button4=button4; button5=button5; button6=dpi; numpad1=1; numpad2=2; numpad3=3; numpad4=4; numpad5=5; numpad6=6; numpad7=7; numpad8=8; numpad9=9; numpad10=0; numpad11=-; numpad12=equal; scrollup=scrollup; scrolldown=scrolldown; layout=qwerty)", }, }, "battery_level": { diff --git a/rivalcfg/handlers/buttons/buttons.py b/rivalcfg/handlers/buttons/buttons.py index 48dee6eb..f36c5fe8 100644 --- a/rivalcfg/handlers/buttons/buttons.py +++ b/rivalcfg/handlers/buttons/buttons.py @@ -327,6 +327,16 @@ def process_value(setting_info, mapping): else: raise ValueError("Unknown button, key or action '%s'" % value) + if "split_packet_at" in setting_info: + # If split_packet_at is defined, the packet will be split at the given indexes + # Each part will be prefixed with the number of the part + split_packet_at = setting_info["split_packet_at"] + packets = [] + for i, split_index in enumerate(split_packet_at): + start_index = split_packet_at[i-1] if i != 0 else 0 + packets.append([i] + packet[start_index:split_index]) + packets.append([len(split_packet_at)] + packet[split_packet_at[-1]:]) + return packets return packet diff --git a/rivalcfg/mouse.py b/rivalcfg/mouse.py index a0a77db6..e74bf2b8 100644 --- a/rivalcfg/mouse.py +++ b/rivalcfg/mouse.py @@ -331,31 +331,35 @@ def __getattr__(self, name): suffix = setting_info["command_suffix"] def _exec_command(*args): - data = [] + packets = [] if handler_name: - data = getattr(handlers, handler_name).process_value( + packets = getattr(handlers, handler_name).process_value( setting_info, *args ) - # Write data to the device - self._hid_write( - report_type=setting_info["report_type"], - data=helpers.merge_bytes(setting_info["command"], data, suffix), - packet_length=packet_length, - ) - # Readback when required - response = None - if "readback_length" in setting_info and setting_info["readback_length"]: - response = self._hid_device.read( - setting_info["readback_length"], - timeout_ms=200, + if not isinstance(packets[0] if packets else [], list): + # Make sure packets is a list of packets and not a single packet + packets = [packets] + responses = [] + for data in packets: + # Write data to the device + self._hid_write( + report_type=setting_info["report_type"], + data=helpers.merge_bytes(setting_info["command"], data, suffix), + packet_length=packet_length, ) + # Readback when required + if "readback_length" in setting_info and setting_info["readback_length"]: + responses.append(self._hid_device.read( + setting_info["readback_length"], + timeout_ms=200, + )) # Save settings if len(args) == 1: self.mouse_settings.set(setting_name, args[0]) else: self.mouse_settings.set(setting_name, args) # - return response + return responses[0] if responses else None return _exec_command From 4a8f45f1029d68621e264946ffd1101613745ba6 Mon Sep 17 00:00:00 2001 From: Zebreus Date: Mon, 10 Mar 2025 19:55:09 +0100 Subject: [PATCH 3/3] Add documentation for aerox 9 button mapping --- doc/devices/aerox9_wireless.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/devices/aerox9_wireless.rst b/doc/devices/aerox9_wireless.rst index 9d69bd0d..4ec35728 100644 --- a/doc/devices/aerox9_wireless.rst +++ b/doc/devices/aerox9_wireless.rst @@ -15,7 +15,6 @@ Missing Features The following feature are currently not supported by Rivalcfg: * Smart illumination -* Button mapping Command-Line Usage @@ -78,6 +77,12 @@ Default Lighting .. include:: ./_default_lighting_reactive.rst +Buttons +------- + +.. include:: ./_buttons.rst + + Python API ----------