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 ---------- diff --git a/rivalcfg/devices/aerox9_wireless_wired.py b/rivalcfg/devices/aerox9_wireless_wired.py index bf0ea70e..898b91f1 100644 --- a/rivalcfg/devices/aerox9_wireless_wired.py +++ b/rivalcfg/devices/aerox9_wireless_wired.py @@ -134,6 +134,47 @@ }, "default": "rainbow", }, + "buttons_mapping": { + "label": "Buttons mapping", + "description": "Set the mapping of the buttons", + "cli": ["-b", "--buttons"], + "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, + "command": [0x2A], + "split_packet_at": [30, 60], + "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"}, + "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, + "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; 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": { "report_type": usbhid.HID_REPORT_TYPE_OUTPUT, 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