diff options
| author | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2025-11-20 23:39:18 +0100 |
|---|---|---|
| committer | Anna (navi) Figueiredo Gomes <navi@vlhl.dev> | 2025-11-20 23:39:18 +0100 |
| commit | 1e637faf644a5f2262a83ca1394faa3003c3d1e3 (patch) | |
| tree | 774e30f5eda251a2326d83800fd2d76088815ddc /src/waypad.c | |
| download | waypad-master.tar.xz | |
Diffstat (limited to 'src/waypad.c')
| -rw-r--r-- | src/waypad.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/src/waypad.c b/src/waypad.c new file mode 100644 index 0000000..ffbe691 --- /dev/null +++ b/src/waypad.c @@ -0,0 +1,141 @@ +#define _XOPEN_SOURCE +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <spawn.h> +#include <unistd.h> +#include <err.h> +#include <errno.h> +#include <sys/poll.h> + +#include <libevdev/libevdev.h> + +#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 <config>", 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; +} |
