From 121a843071ec01503f0165e25e3269880e052a2e Mon Sep 17 00:00:00 2001 From: "Thomas H.P. Andersen" Date: Tue, 29 Sep 2020 00:25:42 +0200 Subject: [PATCH] WIP: sinowealth: read button mapping --- src/driver-sinowealth.c | 112 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/src/driver-sinowealth.c b/src/driver-sinowealth.c index 54522477..abee2099 100644 --- a/src/driver-sinowealth.c +++ b/src/driver-sinowealth.c @@ -29,8 +29,10 @@ #define SINOWEALTH_REPORT_ID_CMD 0x5 #define SINOWEALTH_CMD_FIRMWARE_VERSION 0x1 #define SINOWEALTH_CMD_GET_CONFIG 0x11 +#define SINOWEALTH_CMD_GET_BUTTONS 0x12 #define SINOWEALTH_CONFIG_SIZE 520 #define SINOWEALTH_CONFIG_SIZE_USED 131 +#define SINOWEALTH_BUTTON_SIZE 88 #define SINOWEALTH_XY_INDEPENDENT 0x80 @@ -40,6 +42,9 @@ #define SINOWEALTH_RGB_BRIGHTNESS_BITS 0xF0 #define SINOWEALTH_RGB_SPEED_BITS 0x0F +#define SINOWEALTH_BUTTON_TYPE_BUTTON 0x11 +#define SINOWEALTH_BUTTON_TYPE_KEY 0x21 + struct sinowealth_rgb8 { uint8_t r, g, b; } __attribute__((packed)); @@ -330,6 +335,106 @@ sinowealth_read_profile(struct ratbag_profile *profile) return 0; } +struct sinowealth_button_mapping { + uint8_t raw; + struct ratbag_button_action action; +}; +static struct sinowealth_button_mapping sinowealth_button_mapping[] = { + { 0x01, BUTTON_ACTION_BUTTON(1) }, + { 0x02, BUTTON_ACTION_BUTTON(2) }, + { 0x04, BUTTON_ACTION_BUTTON(3) }, + { 0x08, BUTTON_ACTION_BUTTON(5) }, + { 0x10, BUTTON_ACTION_BUTTON(4) }, +}; + +static const struct ratbag_button_action* +sinowealth_raw_to_button_action(uint8_t data) +{ + struct sinowealth_button_mapping *mapping; + + ARRAY_FOR_EACH(sinowealth_button_mapping, mapping) { + if (mapping->raw == data) + return &mapping->action; + } + + return NULL; +} + +static int +sinowealth_read_buttons(struct ratbag_profile *profile) +{ + struct ratbag_device *device = profile->device; + struct ratbag_button *button; + enum ratbag_button_type button_types[8] = {RATBAG_BUTTON_TYPE_UNKNOWN}; + uint8_t buf[SINOWEALTH_BUTTON_SIZE] = {0}; + uint8_t cmd[6] = {SINOWEALTH_REPORT_ID_CMD, SINOWEALTH_CMD_GET_BUTTONS}; + int rc, offset; + + rc = ratbag_hidraw_set_feature_report(device, SINOWEALTH_REPORT_ID_CMD, cmd, sizeof(cmd)); + if (rc != sizeof(cmd)) { + log_error(device->ratbag, "Error while sending read config command: %d\n", rc); + return -1; + } + + rc = ratbag_hidraw_get_feature_report(device, SINOWEALTH_REPORT_ID_CONFIG, buf, sizeof(buf)); + if (rc != sizeof(buf)) { + log_error(device->ratbag, "Could not read device button configuration: %d\n", rc); + return -1; + } + + button_types[0] = RATBAG_BUTTON_TYPE_LEFT; + button_types[1] = RATBAG_BUTTON_TYPE_RIGHT; + button_types[2] = RATBAG_BUTTON_TYPE_MIDDLE; + button_types[3] = RATBAG_BUTTON_TYPE_THUMB; + button_types[4] = RATBAG_BUTTON_TYPE_THUMB2; + button_types[5] = RATBAG_BUTTON_TYPE_RESOLUTION_UP; + button_types[6] = RATBAG_BUTTON_TYPE_RESOLUTION_DOWN; + button_types[7] = RATBAG_BUTTON_TYPE_THUMB3; + + ratbag_profile_for_each_button(profile, button) { + ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_BUTTON); + ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL); + ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_KEY); + ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_MACRO); + + button->type = button_types[button->index]; + + offset = 8 + button->index * 4; + + if (buf[offset + 0] == SINOWEALTH_BUTTON_TYPE_BUTTON) { + const struct ratbag_button_action *action; + action = sinowealth_raw_to_button_action(buf[offset + 1]); + if (action) + ratbag_button_set_action(button, action); + } else if (buf[offset + 0] == SINOWEALTH_BUTTON_TYPE_KEY) { + unsigned int key, modifiers; + int rc; + + key = ratbag_hidraw_get_keycode_from_keyboard_usage(device, buf[offset + 2]); + + modifiers = 0; + if (buf[offset + 1] & 0x01) + modifiers |= MODIFIER_LEFTCTRL; + if (buf[offset + 1] & 0x02) + modifiers |= MODIFIER_LEFTSHIFT; + if (buf[offset + 1] & 0x04) + modifiers |= MODIFIER_LEFTALT; + if (buf[offset + 1] & 0x08) + modifiers |= MODIFIER_LEFTMETA; + + rc = ratbag_button_macro_new_from_keycode(button, key, modifiers); + if (rc < 0) { + log_error(device->ratbag, + "Error while reading button %d\n", + button->index); + button->action.type = RATBAG_BUTTON_ACTION_TYPE_NONE; + } + } + } + + return 0; +} + static void sinowealth_init_profile(struct ratbag_device *device) { @@ -343,7 +448,6 @@ sinowealth_init_profile(struct ratbag_device *device) dpirange = ratbag_device_data_sinowealth_get_dpi_range(device->data); button_count = ratbag_device_data_sinowealth_get_button_count(device->data); led_count = ratbag_device_data_sinowealth_get_led_count(device->data); - /* TODO: Button remapping */ if (!dpirange) { @@ -423,6 +527,12 @@ sinowealth_probe(struct ratbag_device *device) goto err; } + rc = sinowealth_read_buttons(profile); + if (rc) { + rc = -ENODEV; + goto err; + } + return 0; err: