summaryrefslogtreecommitdiff
path: root/src/waypad.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/waypad.c')
-rw-r--r--src/waypad.c141
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;
+}