#define _XOPEN_SOURCE #include #include #include #include #include #include #include #include #include #include "waypad.h" #include "util.h" bool verbose = false; static void cleanup() { free_gamepads(); } extern char **environ; void handle_key_event(struct gamepad *pad, struct action *action, bool pressed) { switch (action->type) { case ACTION_NONE: return; case ACTION_EXEC: if (!pressed) return; pid_t pid; if ((errno = posix_spawnp(&pid, action->exec[0], NULL, NULL, action->exec, environ)) != 0) warn("failed to exec %s", action->exec[0]); return; case ACTION_KEY: if (pressed) uinput_keyboard_press(action->key.mod, action->key.code); else uinput_keyboard_release(action->key.mod, action->key.code); break; case ACTION_CLICK: if (pressed) uinput_mouse_press(action->click); else uinput_mouse_release(action->click); break; case ACTION_MODE: if (!pressed) break; if (action->mode == pad->modes.current) { warnx("switching to base mode"); pad->modes.current = &pad->modes.base; } else { warnx("switching to mode %s", action->mode->name); pad->modes.current = action->mode; } break; default: todo(); break; } } void handle_axis_event(struct action *action, int input) { int value = input - action->old_value; action->old_value = input; if (input > 1500 || input < -1500) return; switch (action->type) { case ACTION_NONE: return; case ACTION_MOUSE: switch (action->mouse) { case MOUSE_X: uinput_mouse_rel_move(value / 100, 0); break; case MOUSE_Y: uinput_mouse_rel_move(0, -(value / 100)); break; } return; default: todo(); return; } } void handle_event(struct gamepad *pad, struct input_event ev) { struct action *action; switch (ev.type) { case EV_KEY: action = &pad->modes.current->buttons[pad->map.button[ev.code - BTN_MISC]]; handle_key_event(pad, action, ev.value); return; case EV_ABS: action = &pad->modes.current->buttons[pad->map.axis[ev.code]]; handle_axis_event(action, ev.value); return; } } int main(int argc, char **argv) { if (argc < 2) errx(EXIT_FAILURE, "usage: %s ", argv[0]); if (!load_gamepads()) errx(EXIT_FAILURE, "failed to load gamepads"); if (!load_config(argv[1])) errx(EXIT_FAILURE, "failed to load configuration file"); if (!uinput_mouse_init()) errx(EXIT_FAILURE, "failed to create uinput mouse"); if (!uinput_keyboard_init()) errx(EXIT_FAILURE, "failed to create uinput keyboard"); atexit(cleanup); struct pollfd fds[gamepads.len]; for (size_t i = 0; i < gamepads.len; i++) { fds[i] = (struct pollfd) { .fd = libevdev_get_fd(gamepads.loaded[i].dev), .events = POLLIN }; } while (true) { if (poll(fds, gamepads.len, -1) < 0) continue; for (size_t i = 0; i < gamepads.len; i++) { struct input_event ev; int rc; if ((rc = libevdev_next_event(gamepads.loaded[i].dev, LIBEVDEV_READ_FLAG_NORMAL, &ev)) == 0) handle_event(&gamepads.loaded[i], ev); else if (rc != -EAGAIN) warnx("libevdev next event: %s.", strerror(-rc)); } } return 0; }