#include #include #include #include #include #include "waypad.h" #include "util.h" void add_exec(struct action *action, struct scfg_directive *exec) { size_t argc = exec->params_len - 1; action->type = ACTION_EXEC; action->exec = calloc(argc + 1, sizeof(*action->exec)); for (size_t i = 0; i < argc; i++) action->exec[i] = strdup(exec->params[i + 1]); } void add_mouse(struct action *action, struct scfg_directive *mouse) { if (mouse->params_len < 2) // mouse return; action->type = ACTION_CLICK; if (strcmp(mouse->params[1], "left") == 0) action->click = BTN_LEFT; else if (strcmp(mouse->params[1], "right") == 0) action->click = BTN_RIGHT; else if (strcmp(mouse->params[1], "center") == 0) action->click = BTN_MIDDLE; } static const struct { const char *name; enum keyboard_modifier mod; } mod_map[] = { { "shift", KEYMOD_LSHIFT }, { "lshift", KEYMOD_LSHIFT }, { "rshift", KEYMOD_RSHIFT }, { "ctrl", KEYMOD_LCTRL }, { "lctrl", KEYMOD_LCTRL }, { "rctrl", KEYMOD_RCTRL }, { "alt", KEYMOD_LALT }, { "lalt", KEYMOD_LALT }, { "ralt", KEYMOD_RALT }, { "super", KEYMOD_LMETA }, { "meta", KEYMOD_LMETA }, { "lmeta", KEYMOD_LMETA }, { "rmeta", KEYMOD_RMETA }, }; void add_key(struct action *action, struct scfg_directive *key) { enum keyboard_modifier mod = 0; const char *param; size_t i; if (key->params_len < 2) // key [...] return; for (i = 1; i < key->params_len - 1; i++) for (size_t j = 0; j < lenghtof(mod_map); j++) if (strcmp(mod_map[j].name, key->params[i]) == 0) mod |= mod_map[j].mod; param = key->params[i]; char keysym[strlen(param) + sizeof("KEY_")]; char *sym = stpcpy(keysym, "KEY_"); for (i = 0; param[i]; i++) sym[i] = toupper(param[i]); sym[i] = '\0'; action->type = ACTION_KEY; action->key.mod = mod; action->key.code = libevdev_event_code_from_code_name(keysym); if (action->key.code == -1) warn("failed to find evdev codename %s", keysym); } void add_mode(struct gamepad *pad, struct action *action, struct scfg_directive *mode_bind) { if (mode_bind->params_len < 2) // mode return; action->type = ACTION_MODE; action->mode = get_make_mode(pad, mode_bind->params[1]); } static void handle_buttons(struct gamepad *pad, struct scfg_block *buttons) { for (size_t i = 0; i < buttons->directives_len; i++) { struct scfg_directive *button_bind = &buttons->directives[i]; size_t action_idx; if (sscanf(button_bind->name, "btn%zu", &action_idx) != 1) { enum gamepad_button map_idx = str_to_button(button_bind->name); if (map_idx == GAMEPAD_BUTTON_INVALID) continue; action_idx = pad->mapping->buttons[map_idx]; } if (action_idx >= pad->nbuttons) { warn("invalid button \"%s\"", button_bind->name); continue; } struct action *action = &pad->modes.current->buttons[action_idx]; if (button_bind->params_len < 2) continue; if (strcmp(button_bind->params[0], "exec") == 0) add_exec(action, button_bind); else if (strcmp(button_bind->params[0], "key") == 0) add_key(action, button_bind); else if (strcmp(button_bind->params[0], "mouse") == 0) add_mouse(action, button_bind); else if (strcmp(button_bind->params[0], "mode") == 0) add_mode(pad, action, button_bind); else warn("unknown command %s.", button_bind->params[0]); } } static void handle_axis(struct gamepad *pad, struct scfg_block *axis) { for (size_t i = 0; i < axis->directives_len; i++) { struct scfg_directive *axis_bind = &axis->directives[i]; size_t action_idx; if (sscanf(axis_bind->name, "axis%zu", &action_idx) != 1) { enum gamepad_axis map_idx = str_to_axis(axis_bind->name); if (map_idx == GAMEPAD_AXIS_INVALID) continue; action_idx = pad->mapping->axis[map_idx]; } if (action_idx >= pad->naxis) { warn("invalid axis \"%s\"", axis_bind->name); continue; } if (axis_bind->params_len < 2) continue; struct action *action = &pad->modes.current->axis[action_idx]; action->type = ACTION_MOUSE; switch (axis_bind->params[1][0]) { case 'x': action->mouse = MOUSE_X; break; case 'y': action->mouse = MOUSE_Y; break; default: continue; } } } static void handle_mode(struct gamepad *pad, const char *name, struct scfg_block *mode) { if (!name) return; pad->modes.current = get_make_mode(pad, name); for (size_t i = 0; i < mode->directives_len; i++) { struct scfg_directive *section = &mode->directives[i]; if (strcmp(section->name, "button") == 0) handle_buttons(pad, §ion->children); else if (strcmp(section->name, "axis") == 0) handle_axis(pad, §ion->children); else if (strcmp(section->name, "mode") == 0) warn("can't nest modes."); } pad->modes.current = &pad->modes.base; } static void handle_gamepad(struct gamepad *pad, struct scfg_block *cfg) { for (size_t i = 0; i < cfg->directives_len; i++) { struct scfg_directive *section = &cfg->directives[i]; if (strcmp(section->name, "button") == 0) handle_buttons(pad, §ion->children); else if (strcmp(section->name, "axis") == 0) handle_axis(pad, §ion->children); else if (strcmp(section->name, "mode") == 0) handle_mode(pad, section->params_len >= 1 ? section->params[0] : NULL, §ion->children); } } bool load_config(const char *path) { struct scfg_block config; if (scfg_load_file(&config, path) != 0) return false; for (size_t i = 0; i < config.directives_len; i++) { struct gamepad *pad = find_gamepad(config.directives[i].name); if (!pad) { fprintf(stderr, "\"%s\" not found.\n", config.directives[i].name); continue; } handle_gamepad(pad, &config.directives[i].children); } return true; }