diff --git a/src/libratbag-private.h b/src/libratbag-private.h index 42ddc021..0ffafd87 100644 --- a/src/libratbag-private.h +++ b/src/libratbag-private.h @@ -355,6 +355,15 @@ struct ratbag_button_macro { struct ratbag_macro macro; }; +#define MODIFIER_LEFTCTRL (1 << 0) +#define MODIFIER_LEFTSHIFT (1 << 1) +#define MODIFIER_LEFTALT (1 << 2) +#define MODIFIER_LEFTMETA (1 << 3) +#define MODIFIER_RIGHTCTRL (1 << 4) +#define MODIFIER_RIGHTSHIFT (1 << 5) +#define MODIFIER_RIGHTALT (1 << 6) +#define MODIFIER_RIGHTMETA (1 << 7) + struct ratbag_button_action { enum ratbag_button_action_type type; union ratbag_btn_action { @@ -478,6 +487,19 @@ ratbag_button_action_match(const struct ratbag_button_action *action, return 0; } +int +ratbag_action_macro_num_keys(struct ratbag_button_action *action); + +int +ratbag_button_macro_new_from_keycode(struct ratbag_button *button, + unsigned int key, + unsigned int modifiers); + +int +ratbag_action_keycode_from_macro(struct ratbag_button_action *action, + unsigned int *key_out, + unsigned int *modifiers_out); + static inline void ratbag_resolution_set_resolution(struct ratbag_resolution *res, int dpi_x, int dpi_y, int hz) diff --git a/src/libratbag.c b/src/libratbag.c index 041b7b86..bf032e17 100644 --- a/src/libratbag.c +++ b/src/libratbag.c @@ -1909,3 +1909,167 @@ ratbag_button_macro_new(const char *name) return macro; } + +struct ratbag_modifier_mapping { + unsigned int modifier_mask; + unsigned int key; +}; + +struct ratbag_modifier_mapping ratbag_modifier_mapping[] = { + { MODIFIER_LEFTCTRL, KEY_LEFTCTRL }, + { MODIFIER_LEFTSHIFT, KEY_LEFTSHIFT }, + { MODIFIER_LEFTALT, KEY_LEFTALT }, + { MODIFIER_LEFTMETA, KEY_LEFTMETA }, + { MODIFIER_RIGHTCTRL, KEY_RIGHTCTRL }, + { MODIFIER_RIGHTSHIFT, KEY_RIGHTSHIFT }, + { MODIFIER_RIGHTALT, KEY_RIGHTALT }, + { MODIFIER_RIGHTMETA, KEY_RIGHTMETA }, +}; + +int +ratbag_button_macro_new_from_keycode(struct ratbag_button *button, + unsigned int key, + unsigned int modifiers) +{ + struct ratbag_button_macro *macro; + struct ratbag_modifier_mapping *mapping; + int i; + + macro = ratbag_button_macro_new("key"); + i = 0; + + ARRAY_FOR_EACH(ratbag_modifier_mapping, mapping) { + if (modifiers & mapping->modifier_mask) + ratbag_button_macro_set_event(macro, + i++, + RATBAG_MACRO_EVENT_KEY_PRESSED, + mapping->key); + } + + ratbag_button_macro_set_event(macro, + i++, + RATBAG_MACRO_EVENT_KEY_PRESSED, + key); + ratbag_button_macro_set_event(macro, + i++, + RATBAG_MACRO_EVENT_KEY_RELEASED, + key); + + ARRAY_FOR_EACH(ratbag_modifier_mapping, mapping) { + if (modifiers & mapping->modifier_mask) + ratbag_button_macro_set_event(macro, + i++, + RATBAG_MACRO_EVENT_KEY_RELEASED, + mapping->key); + } + + ratbag_button_copy_macro(button, macro); + ratbag_button_macro_unref(macro); + + return 0; +} + +int +ratbag_action_macro_num_keys(struct ratbag_button_action *action) +{ + struct ratbag_macro *macro = action->macro; + int i, count; + + count = 0; + for (i = 0; i < MAX_MACRO_EVENTS; i++) { + struct ratbag_macro_event event; + + event = macro->events[i]; + if (event.type == RATBAG_MACRO_EVENT_KEY_PRESSED) + { + switch(event.event.key) { + case KEY_LEFTCTRL: + case KEY_LEFTSHIFT: + case KEY_LEFTALT: + case KEY_LEFTMETA: + case KEY_RIGHTCTRL: + case KEY_RIGHTSHIFT: + case KEY_RIGHTALT: + case KEY_RIGHTMETA: + break; + default: + count++; + } + } + } + + return count; +} + +int +ratbag_action_keycode_from_macro(struct ratbag_button_action *action, + unsigned int *key_out, + unsigned int *modifiers_out) +{ + struct ratbag_macro *macro = action->macro; + unsigned int key = KEY_RESERVED; + unsigned int modifiers = 0; + unsigned int i; + + if (!macro || action->type != RATBAG_BUTTON_ACTION_TYPE_MACRO) + return -EINVAL; + + if (macro->events[0].type == RATBAG_MACRO_EVENT_NONE) + return -EINVAL; + + if (ratbag_action_macro_num_keys(action) != 1) + return -EINVAL; + + for (i = 0; i < MAX_MACRO_EVENTS; i++) { + struct ratbag_macro_event event; + + event = macro->events[i]; + switch (event.type) { + case RATBAG_MACRO_EVENT_INVALID: + return -EINVAL; + case RATBAG_MACRO_EVENT_NONE: + return 0; + case RATBAG_MACRO_EVENT_KEY_PRESSED: + switch(event.event.key) { + case KEY_LEFTCTRL: modifiers |= MODIFIER_LEFTCTRL; break; + case KEY_LEFTSHIFT: modifiers |= MODIFIER_LEFTSHIFT; break; + case KEY_LEFTALT: modifiers |= MODIFIER_LEFTALT; break; + case KEY_LEFTMETA: modifiers |= MODIFIER_LEFTMETA; break; + case KEY_RIGHTCTRL: modifiers |= MODIFIER_RIGHTCTRL; break; + case KEY_RIGHTSHIFT: modifiers |= MODIFIER_RIGHTSHIFT; break; + case KEY_RIGHTALT: modifiers |= MODIFIER_RIGHTALT; break; + case KEY_RIGHTMETA: modifiers |= MODIFIER_RIGHTMETA; break; + default: + if (key != KEY_RESERVED) + return -EINVAL; + + key = event.event.key; + } + break; + case RATBAG_MACRO_EVENT_KEY_RELEASED: + switch(event.event.key) { + case KEY_LEFTCTRL: modifiers &= ~MODIFIER_LEFTCTRL; break; + case KEY_LEFTSHIFT: modifiers &= ~MODIFIER_LEFTSHIFT; break; + case KEY_LEFTALT: modifiers &= ~MODIFIER_LEFTALT; break; + case KEY_LEFTMETA: modifiers &= ~MODIFIER_LEFTMETA; break; + case KEY_RIGHTCTRL: modifiers &= ~MODIFIER_RIGHTCTRL; break; + case KEY_RIGHTSHIFT: modifiers &= ~MODIFIER_RIGHTSHIFT; break; + case KEY_RIGHTALT: modifiers &= ~MODIFIER_RIGHTALT; break; + case KEY_RIGHTMETA: modifiers &= ~MODIFIER_RIGHTMETA; break; + default: + if (event.event.key != key) + return -EINVAL; + + *key_out = key; + *modifiers_out = modifiers; + return 1; + } + case RATBAG_MACRO_EVENT_WAIT: + break; + default: + return -EINVAL; + } + } + + return -EINVAL; +}