diff --git a/src/driver-etekcity.c b/src/driver-etekcity.c index 4676a47d..06260ca0 100644 --- a/src/driver-etekcity.c +++ b/src/driver-etekcity.c @@ -598,15 +598,20 @@ etekcity_read_button(struct ratbag_button *button) button->index, button->profile->index, rc < 0 ? strerror(-rc) : "not read enough", rc); } else { - log_info(device->ratbag, - "macro on button %d of profile %d is named '%s', and contains %d events:\n", - button->index, button->profile->index, - macro->name, macro->length); + ratbag_button_set_macro(button); + log_raw(device->ratbag, + "macro on button %d of profile %d is named '%s', and contains %d events:\n", + button->index, button->profile->index, + macro->name, macro->length); for (j = 0; j < macro->length; j++) { - log_info(device->ratbag, - " - %s %s\n", - libevdev_event_code_get_name(EV_KEY, macro_mapping[macro->keys[j].keycode]), - macro->keys[j].flag & 0x80 ? "released" : "pressed"); + ratbag_button_set_macro_event(button, + j, + macro->keys[j].flag & 0x80 ? RATBAG_MACRO_EVENT_KEY_RELEASED : RATBAG_MACRO_EVENT_KEY_PRESSED, + macro_mapping[macro->keys[j].keycode]); + log_raw(device->ratbag, + " - %s %s\n", + libevdev_event_code_get_name(EV_KEY, macro_mapping[macro->keys[j].keycode]), + macro->keys[j].flag & 0x80 ? "released" : "pressed"); } } msleep(10); diff --git a/src/libratbag-private.h b/src/libratbag-private.h index 8ff3a577..8dd263a0 100644 --- a/src/libratbag-private.h +++ b/src/libratbag-private.h @@ -247,6 +247,21 @@ struct ratbag_profile { { .type = RATBAG_BUTTON_ACTION_TYPE_MACRO, \ /* FIXME: add the macro keys */ } +struct ratbag_macro_event { + enum ratbag_macro_event_type type; + union ratbag_macro_evnt { + unsigned int key; + unsigned int timeout; + } event; +}; + +#define MAX_MACRO_EVENTS 64 +struct ratbag_macro { + const char *name; + const char *group; + struct ratbag_macro_event events[MAX_MACRO_EVENTS]; +}; + struct ratbag_button_action { enum ratbag_button_action_type type; union ratbag_btn_action { @@ -256,8 +271,8 @@ struct ratbag_button_action { unsigned int key; /* action_type == key */ /* FIXME: modifiers */ } key; - /* FIXME: MACRO */ } action; + struct ratbag_macro *macro; /* dynamically allocated, so kept aside */ }; struct ratbag_button { @@ -338,7 +353,7 @@ ratbag_button_action_match(const struct ratbag_button_action *action, case RATBAG_BUTTON_ACTION_TYPE_SPECIAL: return match->action.special == action->action.special; case RATBAG_BUTTON_ACTION_TYPE_MACRO: - /* FIXME: currently, do nothing */ + return 1; default: break; } diff --git a/src/libratbag.c b/src/libratbag.c index fc38ec5e..0c240865 100644 --- a/src/libratbag.c +++ b/src/libratbag.c @@ -1204,6 +1204,8 @@ static void ratbag_button_destroy(struct ratbag_button *button) { list_remove(&button->link); + if (button->action.macro) + free(button->action.macro); free(button); } @@ -1284,3 +1286,97 @@ ratbag_resolution_get_user_data(const struct ratbag_resolution *ratbag_resolutio { return ratbag_resolution->userdata; } + +LIBRATBAG_EXPORT int +ratbag_button_set_macro(struct ratbag_button *button) +{ + struct ratbag_macro *macro; + + if (!button->action.macro) + button->action.macro = zalloc(sizeof(*macro)); + else + memset(button->action.macro, 0, sizeof(*macro)); + + button->action.type = RATBAG_BUTTON_ACTION_TYPE_MACRO; + + return 0; +} + +LIBRATBAG_EXPORT int +ratbag_button_set_macro_event(struct ratbag_button *button, + unsigned int index, + enum ratbag_macro_event_type type, + unsigned int data) +{ + struct ratbag_macro *macro; + + if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO || + index >= MAX_MACRO_EVENTS) + return -EINVAL; + + macro = button->action.macro; + + switch (type) { + case RATBAG_MACRO_EVENT_KEY_PRESSED: + case RATBAG_MACRO_EVENT_KEY_RELEASED: + macro->events[index].type = type; + macro->events[index].event.key = data; + break; + case RATBAG_MACRO_EVENT_WAIT: + macro->events[index].type = type; + macro->events[index].event.timeout = data; + break; + case RATBAG_MACRO_EVENT_NONE: + macro->events[index].type = type; + break; + default: + return -EINVAL; + } + + return 0; +} + +LIBRATBAG_EXPORT enum ratbag_macro_event_type +ratbag_button_get_macro_event_type(struct ratbag_button *button, unsigned int index) +{ + if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO || + index >= MAX_MACRO_EVENTS) + return RATBAG_MACRO_EVENT_INVALID; + + return button->action.macro->events[index].type; +} + +LIBRATBAG_EXPORT int +ratbag_button_get_macro_event_key(struct ratbag_button *button, unsigned int index) +{ + struct ratbag_macro *macro; + + if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO || + index >= MAX_MACRO_EVENTS) + return -EINVAL; + + macro = button->action.macro; + + if (macro->events[index].type != RATBAG_MACRO_EVENT_KEY_PRESSED && + macro->events[index].type != RATBAG_MACRO_EVENT_KEY_RELEASED) + return -EINVAL; + + return macro->events[index].event.key; +} + +LIBRATBAG_EXPORT int +ratbag_button_get_macro_event_timeout(struct ratbag_button *button, unsigned int index) +{ + struct ratbag_macro *macro; + + if (button->action.type != RATBAG_BUTTON_ACTION_TYPE_MACRO || + index >= MAX_MACRO_EVENTS) + return -EINVAL; + + macro = button->action.macro; + + if (macro->events[index].type != RATBAG_MACRO_EVENT_WAIT) + return -EINVAL; + + return macro->events[index].event.timeout; +} diff --git a/src/libratbag.h b/src/libratbag.h index 4b6116ea..11d50b38 100644 --- a/src/libratbag.h +++ b/src/libratbag.h @@ -1259,19 +1259,95 @@ ratbag_button_disable(struct ratbag_button *button); /** * @ingroup button * - * FIXME: no idea at this point + * Macro event types describing the event. */ -unsigned int -ratbag_button_get_macro(struct ratbag_button *button); +enum ratbag_macro_event_type { + RATBAG_MACRO_EVENT_INVALID = -1, + RATBAG_MACRO_EVENT_NONE = 0, + RATBAG_MACRO_EVENT_KEY_PRESSED, + RATBAG_MACRO_EVENT_KEY_RELEASED, + RATBAG_MACRO_EVENT_WAIT, +}; /** * @ingroup button * - * FIXME: no idea at this point + * If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, + * this function returns the macro event type configured for the event at the + * given index. + * + * If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, + * this function returns @ref RATBAG_MACRO_EVENT_INVALID. + * + * @param button A previously initialized ratbag button + * @param index An index of the event within the macro we are interested in. + * + * @return The type of the event at the given index */ -unsigned int +enum ratbag_macro_event_type +ratbag_button_get_macro_event_type(struct ratbag_button *button, unsigned int index); + +/** + * @ingroup button + * + * If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, and if the + * event stored at the given index is @ref RATBAG_MACRO_EVENT_KEY_PRESSED or + * @ref RATBAG_MACRO_EVENT_KEY_RELEASED, this function returns the key code + * configured for the event at the given index. + * + * If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, + * or if the event stored at the given index is not + * @ref RATBAG_MACRO_EVENT_KEY_PRESSED or @ref RATBAG_MACRO_EVENT_KEY_RELEASED, + * this function returns -EINVAL. + * + * @param button A previously initialized ratbag button + * @param index An index of the event within the macro we are interested in. + * + * @return The key of the event at the given index + */ +int +ratbag_button_get_macro_event_key(struct ratbag_button *button, unsigned int index); + +/** + * @ingroup button + * + * If a button's action is @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, and if the + * event stored at the given index is @ref RATBAG_MACRO_EVENT_WAIT, this + * function returns the timeout configured for the event at the given index. + * + * If the button's action type is not @ref RATBAG_BUTTON_ACTION_TYPE_MACRO, + * or if the event stored at the given index is not + * @ref RATBAG_MACRO_EVENT_WAIT, this function returns -EINVAL. + * + * @param button A previously initialized ratbag button + * @param index An index of the event within the macro we are interested in. + * + * @return The tiemout of the event at the given index + */ +int +ratbag_button_get_macro_event_timeout(struct ratbag_button *button, unsigned int index); + +/** + * @ingroup button + * + * Sets the button's action to @ref RATBAG_BUTTON_ACTION_TYPE_MACRO and + * allocates the required memory to store the macro. + */ +int ratbag_button_set_macro(struct ratbag_button *button); +/** + * @ingroup button + * + * Sets the macro's event at the given index to the given type with the + * key code or timeout given. + */ +int +ratbag_button_set_macro_event(struct ratbag_button *button, + unsigned int index, + enum ratbag_macro_event_type type, + unsigned int data); + /** * @ingroup button * diff --git a/src/libratbag.sym b/src/libratbag.sym index bd43ce83..1b1cda5d 100644 --- a/src/libratbag.sym +++ b/src/libratbag.sym @@ -8,12 +8,17 @@ global: ratbag_button_get_type; ratbag_button_get_button; ratbag_button_get_key; + ratbag_button_get_macro_event_type; + ratbag_button_get_macro_event_key; + ratbag_button_get_macro_event_timeout; ratbag_button_get_special; ratbag_button_get_user_data; ratbag_button_has_action_type; ratbag_button_ref; ratbag_button_set_button; ratbag_button_set_key; + ratbag_button_set_macro; + ratbag_button_set_macro_event; ratbag_button_set_special; ratbag_button_set_user_data; ratbag_button_unref; diff --git a/tools/shared.c b/tools/shared.c index b80b518f..56273f42 100644 --- a/tools/shared.c +++ b/tools/shared.c @@ -145,6 +145,48 @@ button_action_key_to_str(struct ratbag_button *button) return strdup(str); } +static const char *strip_ev_key(int key) +{ + const char *str = libevdev_event_code_get_name(EV_KEY, key); + + if (!strncmp(str, "KEY_", 4)) + return str + 4; + return str; +}; + +char * +button_action_macro_to_str(struct ratbag_button *button) +{ + char str[4096] = {0}; + int offset; + unsigned int i; + + offset = snprintf(str, sizeof(str), "macro:"); + for (i = 0; i < MAX_MACRO_EVENTS; i++) { + enum ratbag_macro_event_type type = ratbag_button_get_macro_event_type(button, i); + int key = ratbag_button_get_macro_event_key(button, i); + int timeout = ratbag_button_get_macro_event_timeout(button, i); + + if (type == RATBAG_MACRO_EVENT_NONE) + break; + + switch (type) { + case RATBAG_MACRO_EVENT_KEY_PRESSED: + offset += snprintf(str + offset, sizeof(str) - offset, " %s↓", strip_ev_key(key)); + break; + case RATBAG_MACRO_EVENT_KEY_RELEASED: + offset += snprintf(str + offset, sizeof(str) - offset, " %s↑", strip_ev_key(key)); + break; + case RATBAG_MACRO_EVENT_WAIT: + offset += snprintf(str + offset, sizeof(str) - offset, " %d.%d⏱", timeout / 1000, timeout % 1000); + default: + offset += snprintf(str + offset, sizeof(str) - offset, " ###"); + } + } + + return strdup(str); +} + char * button_action_to_str(struct ratbag_button *button) { @@ -157,7 +199,7 @@ button_action_to_str(struct ratbag_button *button) case RATBAG_BUTTON_ACTION_TYPE_BUTTON: str = button_action_button_to_str(button); break; case RATBAG_BUTTON_ACTION_TYPE_KEY: str = button_action_key_to_str(button); break; case RATBAG_BUTTON_ACTION_TYPE_SPECIAL: str = strdup(button_action_special_to_str(button)); break; - case RATBAG_BUTTON_ACTION_TYPE_MACRO: str = strdup("macro"); break; + case RATBAG_BUTTON_ACTION_TYPE_MACRO: str = button_action_macro_to_str(button); break; case RATBAG_BUTTON_ACTION_TYPE_NONE: str = strdup("none"); break; default: error("type %d unknown\n", type); diff --git a/tools/shared.h b/tools/shared.h index c3c6fc8d..968131f4 100644 --- a/tools/shared.h +++ b/tools/shared.h @@ -37,6 +37,8 @@ #include #include +#define MAX_MACRO_EVENTS 64 + LIBRATBAG_ATTRIBUTE_PRINTF(1, 2) static inline void error(const char *format, ...)