mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-08 07:33:53 +01:00
hidpp20: parse macros
I am pretty sure we could do a better job, but heh. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
This commit is contained in:
@@ -97,6 +97,78 @@ hidpp20drv_read_button_1b04(struct ratbag_button *button)
|
||||
ratbag_button_enable_action_type(button, RATBAG_BUTTON_ACTION_TYPE_SPECIAL);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hidpp20drv_read_macro_key_8100(struct ratbag_device *device, union hidpp20_macro_data *macro)
|
||||
{
|
||||
switch (macro->key.modifier) {
|
||||
case 0x01: return KEY_LEFTCTRL;
|
||||
case 0x02: return KEY_LEFTSHIFT;
|
||||
case 0x04: return KEY_LEFTALT;
|
||||
case 0x08: return KEY_LEFTMETA;
|
||||
case 0x10: return KEY_RIGHTCTRL;
|
||||
case 0x20: return KEY_RIGHTSHIFT;
|
||||
case 0x40: return KEY_RIGHTALT;
|
||||
case 0x80: return KEY_RIGHTMETA;
|
||||
}
|
||||
|
||||
return ratbag_hidraw_get_keycode_from_keyboard_usage(device, macro->key.key);
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_macro_8100(struct ratbag_button *button,
|
||||
struct hidpp20_profile *profile,
|
||||
union hidpp20_button_binding *binding)
|
||||
{
|
||||
struct ratbag_device *device = button->profile->device;
|
||||
union hidpp20_macro_data *macro;
|
||||
unsigned int i, keycode;
|
||||
bool delay = true;
|
||||
|
||||
macro = profile->macros[binding->macro.page];
|
||||
|
||||
ratbag_button_set_macro(button, "macro");
|
||||
i = 0;
|
||||
|
||||
while (macro && macro->any.type != HIDPP20_MACRO_END && i < MAX_MACRO_EVENTS) {
|
||||
switch (macro->any.type) {
|
||||
case HIDPP20_MACRO_DELAY:
|
||||
ratbag_button_set_macro_event(button,
|
||||
i++,
|
||||
RATBAG_MACRO_EVENT_WAIT,
|
||||
macro->delay.time);
|
||||
delay = true;
|
||||
break;
|
||||
case HIDPP20_MACRO_KEY_PRESS:
|
||||
keycode = hidpp20drv_read_macro_key_8100(device, macro);
|
||||
if (!delay)
|
||||
ratbag_button_set_macro_event(button,
|
||||
i++,
|
||||
RATBAG_MACRO_EVENT_WAIT,
|
||||
1);
|
||||
ratbag_button_set_macro_event(button,
|
||||
i++,
|
||||
RATBAG_MACRO_EVENT_KEY_PRESSED,
|
||||
keycode);
|
||||
delay = false;
|
||||
break;
|
||||
case HIDPP20_MACRO_KEY_RELEASE:
|
||||
keycode = hidpp20drv_read_macro_key_8100(device, macro);
|
||||
if (!delay)
|
||||
ratbag_button_set_macro_event(button,
|
||||
i++,
|
||||
RATBAG_MACRO_EVENT_WAIT,
|
||||
1);
|
||||
ratbag_button_set_macro_event(button,
|
||||
i++,
|
||||
RATBAG_MACRO_EVENT_KEY_RELEASED,
|
||||
keycode);
|
||||
delay = false;
|
||||
break;
|
||||
}
|
||||
macro++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
hidpp20drv_read_button_8100(struct ratbag_button *button)
|
||||
{
|
||||
@@ -132,6 +204,9 @@ hidpp20drv_read_button_8100(struct ratbag_button *button)
|
||||
button->action.type = RATBAG_BUTTON_ACTION_TYPE_SPECIAL;
|
||||
button->action.action.special = hidpp20_onboard_profiles_get_special(profile->buttons[button->index].special.special);
|
||||
break;
|
||||
case HIDPP20_BUTTON_MACRO:
|
||||
hidpp20drv_read_macro_8100(button, profile, &profile->buttons[button->index]);
|
||||
break;
|
||||
default:
|
||||
button->action.type = RATBAG_BUTTON_ACTION_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
189
src/hidpp20.c
189
src/hidpp20.c
@@ -1133,6 +1133,166 @@ hidpp20_onboard_profiles_initialize(struct hidpp20_device *device,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20_onboard_profiles_macro_next(struct hidpp20_device *device,
|
||||
uint8_t memory[32],
|
||||
uint16_t *index,
|
||||
union hidpp20_macro_data *macro)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned int step = 1;
|
||||
|
||||
if (*index >= 32 - sizeof(union hidpp20_macro_data)) {
|
||||
hidpp_log_error(&device->base, "error while parsing macro.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
memcpy(macro, &memory[*index], sizeof(union hidpp20_macro_data));
|
||||
|
||||
switch (macro->any.type) {
|
||||
case HIDPP20_MACRO_DELAY:
|
||||
/* fallthrough */
|
||||
case HIDPP20_MACRO_KEY_PRESS:
|
||||
/* fallthrough */
|
||||
case HIDPP20_MACRO_KEY_RELEASE:
|
||||
/* fallthrough */
|
||||
case HIDPP20_MACRO_JUMP:
|
||||
step = 3;
|
||||
rc = -EAGAIN;
|
||||
break;
|
||||
case HIDPP20_MACRO_NOOP:
|
||||
step = 1;
|
||||
rc = -EAGAIN;
|
||||
break;
|
||||
case HIDPP20_MACRO_END:
|
||||
step = 1;
|
||||
return 0;
|
||||
default:
|
||||
hidpp_log_error(&device->base, "unknown tag: 0x%02x\n", macro->any.type);
|
||||
rc = -EFAULT;
|
||||
}
|
||||
|
||||
if ((*index + step) & 0xF0)
|
||||
/* the next item will be on the following chunk */
|
||||
return -ENOMEM;
|
||||
|
||||
*index += step;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20_onboard_profiles_read_macro(struct hidpp20_device *device,
|
||||
uint8_t page, uint8_t offset,
|
||||
union hidpp20_macro_data **return_macro)
|
||||
{
|
||||
uint8_t memory[HIDPP20_PAGE_SIZE];
|
||||
union hidpp20_macro_data *macro = NULL;
|
||||
unsigned count = 0;
|
||||
unsigned index = 0;
|
||||
uint16_t mem_index = 0;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
do {
|
||||
if (count == index) {
|
||||
union hidpp20_macro_data *tmp;
|
||||
|
||||
count += 32;
|
||||
/* manual realloc to have the memory zero-initialized */
|
||||
tmp = zalloc(count * sizeof(union hidpp20_macro_data));
|
||||
if (macro) {
|
||||
memcpy(tmp, macro, (count - 32) * sizeof(union hidpp20_macro_data));
|
||||
free(macro);
|
||||
}
|
||||
macro = tmp;
|
||||
}
|
||||
|
||||
if (rc == -ENOMEM) {
|
||||
offset += mem_index;
|
||||
rc = hidpp20_onboard_profiles_read_memory(device,
|
||||
0,
|
||||
page,
|
||||
offset,
|
||||
memory);
|
||||
if (rc)
|
||||
goto out_err;
|
||||
|
||||
mem_index = 0;
|
||||
}
|
||||
|
||||
rc = hidpp20_onboard_profiles_macro_next(device,
|
||||
memory,
|
||||
&mem_index,
|
||||
¯o[index]);
|
||||
if (rc == -EFAULT)
|
||||
goto out_err;
|
||||
|
||||
if (rc != -ENOMEM) {
|
||||
if (macro[index].any.type == HIDPP20_MACRO_JUMP) {
|
||||
page = macro[index].jump.page;
|
||||
offset = macro[index].jump.offset;
|
||||
mem_index = 0;
|
||||
/* no need to store the jump in memory */
|
||||
index--;
|
||||
/* force memory fetching */
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
} while (rc);
|
||||
|
||||
*return_macro = macro;
|
||||
return index;
|
||||
|
||||
out_err:
|
||||
if (macro)
|
||||
free(macro);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
hidpp20_onboard_profiles_parse_macro(struct hidpp20_device *device,
|
||||
uint8_t page, uint8_t offset,
|
||||
union hidpp20_macro_data **return_macro)
|
||||
{
|
||||
union hidpp20_macro_data *m, *macro = NULL;
|
||||
unsigned i, count = 0;
|
||||
int rc;
|
||||
|
||||
rc = hidpp20_onboard_profiles_read_macro(device, page, offset, ¯o);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
count = rc;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
m = ¯o[i];
|
||||
switch (m->any.type) {
|
||||
case HIDPP20_MACRO_DELAY:
|
||||
m->delay.time = hidpp_be_u16_to_cpu(m->delay.time);
|
||||
break;
|
||||
case HIDPP20_MACRO_KEY_PRESS:
|
||||
break;
|
||||
case HIDPP20_MACRO_KEY_RELEASE:
|
||||
break;
|
||||
case HIDPP20_MACRO_JUMP:
|
||||
break;
|
||||
case HIDPP20_MACRO_END:
|
||||
break;
|
||||
case HIDPP20_MACRO_NOOP:
|
||||
break;
|
||||
default:
|
||||
hidpp_log_error(&device->base, "unknown tag: 0x%02x\n", m->any.type);
|
||||
}
|
||||
}
|
||||
|
||||
*return_macro = macro;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hidpp20_onboard_profiles_allocate(struct hidpp20_device *device,
|
||||
struct hidpp20_profiles **profiles_list)
|
||||
@@ -1177,9 +1337,22 @@ void
|
||||
hidpp20_onboard_profiles_destroy(struct hidpp20_device *device,
|
||||
struct hidpp20_profiles *profiles_list)
|
||||
{
|
||||
struct hidpp20_profile *profile;
|
||||
union hidpp20_macro_data **macro;
|
||||
unsigned i;
|
||||
|
||||
if (!profiles_list)
|
||||
return;
|
||||
|
||||
for (i = 0; i < profiles_list->num_profiles; i++) {
|
||||
profile = &profiles_list->profiles[i];
|
||||
|
||||
ARRAY_FOR_EACH(profile->macros, macro) {
|
||||
if (*macro)
|
||||
free(*macro);
|
||||
}
|
||||
}
|
||||
|
||||
free(profiles_list);
|
||||
}
|
||||
|
||||
@@ -1288,7 +1461,8 @@ union hidpp20_internal_profile {
|
||||
_Static_assert(sizeof(union hidpp20_internal_profile) == HIDPP20_PROFILE_SIZE, "Invalid size");
|
||||
|
||||
static void
|
||||
hidpp20_buttons_to_cpu(struct hidpp20_profile *profile,
|
||||
hidpp20_buttons_to_cpu(struct hidpp20_device *device,
|
||||
struct hidpp20_profile *profile,
|
||||
union hidpp20_button_binding *buttons,
|
||||
unsigned int count)
|
||||
{
|
||||
@@ -1320,6 +1494,17 @@ hidpp20_buttons_to_cpu(struct hidpp20_profile *profile,
|
||||
case HIDPP20_BUTTON_SPECIAL:
|
||||
button->special.special = b->special.special;
|
||||
break;
|
||||
case HIDPP20_BUTTON_MACRO:
|
||||
if (profile->macros[i]) {
|
||||
free(profile->macros[i]);
|
||||
profile->macros[i] = NULL;
|
||||
}
|
||||
hidpp20_onboard_profiles_parse_macro(device,
|
||||
b->macro.page,
|
||||
b->macro.offset,
|
||||
&profile->macros[i]);
|
||||
button->macro.page = i;
|
||||
break;
|
||||
case HIDPP20_BUTTON_DISABLED:
|
||||
break;
|
||||
default:
|
||||
@@ -1396,7 +1581,7 @@ int hidpp20_onboard_profiles_read(struct hidpp20_device *device,
|
||||
profile->dpi[i] = hidpp_get_unaligned_le_u16(&data[2 * i + 3]);
|
||||
}
|
||||
|
||||
hidpp20_buttons_to_cpu(profile, pdata.profile.buttons, profiles_list->num_buttons);
|
||||
hidpp20_buttons_to_cpu(device, profile, pdata.profile.buttons, profiles_list->num_buttons);
|
||||
|
||||
memcpy(profile->name, pdata.profile.name.txt, sizeof(profile->name));
|
||||
/* force terminating '\0' */
|
||||
|
||||
@@ -269,6 +269,7 @@ int hidpp20_adjustable_dpi_set_sensor_dpi(struct hidpp20_device *device,
|
||||
#define HIDPP20_BUTTON_HID_TYPE_KEYBOARD 0x02
|
||||
#define HIDPP20_BUTTON_HID_TYPE_CONSUMER_CONTROL 0x03
|
||||
#define HIDPP20_BUTTON_SPECIAL 0x90
|
||||
#define HIDPP20_BUTTON_MACRO 0x00
|
||||
#define HIDPP20_BUTTON_DISABLED 0xFF
|
||||
|
||||
#define HIDPP20_MODIFIER_KEY_CTRL 0x01
|
||||
@@ -302,12 +303,49 @@ union hidpp20_button_binding {
|
||||
uint8_t type; /* HIDPP20_BUTTON_SPECIAL */
|
||||
uint8_t special;
|
||||
} __attribute__((packed)) special;
|
||||
struct {
|
||||
uint8_t type; /* HIDPP20_BUTTON_MACRO */
|
||||
uint8_t page;
|
||||
uint8_t zero;
|
||||
uint8_t offset;
|
||||
} __attribute__((packed)) macro;
|
||||
struct {
|
||||
uint8_t type; /* PROFILE_BUTTON_TYPE_DISABLED */
|
||||
} disabled;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(union hidpp20_button_binding) == 4, "Invalid size");
|
||||
|
||||
#define HIDPP20_MACRO_NOOP 0x01
|
||||
#define HIDPP20_MACRO_DELAY 0x40
|
||||
#define HIDPP20_MACRO_KEY_PRESS 0x43
|
||||
#define HIDPP20_MACRO_KEY_RELEASE 0x44
|
||||
#define HIDPP20_MACRO_JUMP 0x60
|
||||
#define HIDPP20_MACRO_END 0xff
|
||||
|
||||
union hidpp20_macro_data {
|
||||
struct {
|
||||
uint8_t type;
|
||||
} __attribute__((packed)) any;
|
||||
struct {
|
||||
uint8_t type; /* HIDPP20_MACRO_DELAY */
|
||||
uint16_t time;
|
||||
} __attribute__((packed)) delay;
|
||||
struct {
|
||||
uint8_t type; /* HIDPP20_MACRO_KEY_PRESS or HIDPP20_MACRO_KEY_RELEASE */
|
||||
uint8_t modifier;
|
||||
uint8_t key;
|
||||
} __attribute__((packed)) key;
|
||||
struct {
|
||||
uint8_t type; /* HIDPP20_MACRO_JUMP */
|
||||
uint8_t offset;
|
||||
uint8_t page;
|
||||
} __attribute__((packed)) jump;
|
||||
struct {
|
||||
uint8_t type; /* HIDPP20_MACRO_END */
|
||||
} __attribute__((packed)) end;
|
||||
} __attribute__((packed));
|
||||
_Static_assert(sizeof(union hidpp20_macro_data) == 3, "Invalid size");
|
||||
|
||||
struct hidpp20_profile {
|
||||
uint8_t index;
|
||||
uint8_t enabled;
|
||||
@@ -317,6 +355,7 @@ struct hidpp20_profile {
|
||||
unsigned switched_dpi;
|
||||
uint16_t dpi[5];
|
||||
union hidpp20_button_binding buttons[32];
|
||||
union hidpp20_macro_data *macros[32];
|
||||
};
|
||||
|
||||
struct hidpp20_profiles {
|
||||
|
||||
Reference in New Issue
Block a user