diff options
-rw-r--r-- | libgamepad.h | 2 | ||||
-rw-r--r-- | libgamepad_list_superdevices.c | 48 | ||||
-rw-r--r-- | test-visual.c | 106 |
3 files changed, 136 insertions, 20 deletions
diff --git a/libgamepad.h b/libgamepad.h index 7a046a3..cd574b0 100644 --- a/libgamepad.h +++ b/libgamepad.h @@ -891,7 +891,7 @@ enum libgamepad_game_controller { * Analogue stick at middle thumb position * 4 directional "C" (colour: yellow) buttons at right thumb position * Digital "L" button at left index finger position - * Digital "Z" button at middle index finger position + * Digital "Z" button at middle index finger position (we select BTN_TRIGGER_HAPPY1 for this one) * Digital "R" button at right index finger position * Digital "START" (colour: red) button north of middle thumb position * 2 digital buttons south east of right thumb position diff --git a/libgamepad_list_superdevices.c b/libgamepad_list_superdevices.c index f8c7c4d..57068cb 100644 --- a/libgamepad_list_superdevices.c +++ b/libgamepad_list_superdevices.c @@ -5,7 +5,9 @@ int libgamepad_list_superdevices(char ***devicesp, size_t *ndevicesp) { - char path[PATH_MAX], target[PATH_MAX]; /* TODO do not use PATH_MAX */ + char *path, *target; + size_t path_size, target_size = 256; + const size_t path_size_base = sizeof("/sys/class/input//device/device"); int dirfd; DIR *dir; struct dirent *f; @@ -28,18 +30,48 @@ libgamepad_list_superdevices(char ***devicesp, size_t *ndevicesp) return -1; } + path_size = path_size_base + 255; + path_size = path_size > sizeof("/dev/fd/") + 3 * sizeof(int) ? path_size : sizeof("/dev/fd/") + 3 * sizeof(int); + path = malloc(path_size); + if (!path) + goto fail; + + target = malloc(target_size); + if (!target) + goto fail; + while (errno = 0, (f = readdir(dir))) { if (!strncmp(f->d_name, "event", 5) && isdigit(f->d_name[5])) { + if (path_size_base + strlen(f->d_name) > path_size) { + path_size = path_size_base + strlen(f->d_name); + new = realloc(path, path_size); + if (!new) + goto fail; + path = new; + } stpcpy(stpcpy(stpcpy(path, "/sys/class/input/"), f->d_name), "/device/device"); dirfd = open(path, O_PATH); if (dirfd < 0) continue; + sprintf(path, "/dev/fd/%i", dirfd); - r = readlink(path, target, sizeof(target) - 1); - close(dirfd); - if (r < 0) - continue; - target[r] = '\0'; + for (;;) { + r = readlink(path, target, target_size); + if (r < 0) { + close(dirfd); + goto next; + } + if ((size_t)r < target_size) { + close(dirfd); + target[r] = '\0'; + break; + } + new = realloc(target, target_size += 256); + if (!new) + goto fail; + target = new; + } + if (paths) for (i = 0; i < n; i++) if (!strcmp(paths[i], target)) @@ -61,6 +93,8 @@ libgamepad_list_superdevices(char ***devicesp, size_t *ndevicesp) if (errno) goto fail; + free(path); + free(target); closedir(dir); errno = saved_errno; @@ -72,6 +106,8 @@ fail: for (i = 0; i < n; i++) free(paths[i]); free(paths); + free(path); + free(target); closedir(dir); return -1; } diff --git a/test-visual.c b/test-visual.c index bd3a610..6e2b466 100644 --- a/test-visual.c +++ b/test-visual.c @@ -3,6 +3,8 @@ #include <sys/ioctl.h> #include <assert.h> +#include <poll.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -18,10 +20,29 @@ struct abs_axis { }; +static volatile sig_atomic_t sigwinch_received = 0; +static volatile sig_atomic_t sigint_received = 0; + + +static void +sigwinch_handler(int signo) +{ + (void) signo; + sigwinch_received = 1; +} + + +static void +sigint_handler(int signo) +{ + (void) signo; + sigint_received = 1; +} + + static const char * draw_axis(char buffer[], const struct abs_axis *axis, size_t len) { - /* TODO axis->value can actually be out of bounds */ char value_buf[sizeof(intmax_t) * 3 + 2]; size_t width, x, value_len; #ifdef __GNUC__ @@ -36,7 +57,9 @@ draw_axis(char buffer[], const struct abs_axis *axis, size_t len) value_len = (size_t)sprintf(value_buf, "%ji", axis->value); x = axis->max_len + (width - value_len) / 2; memcpy(&buffer[x], value_buf, value_len); - x = (size_t)(axis->value - axis->min) * len; + x = (size_t)(axis->value < axis->min ? 0 : /* this actually happens */ + axis->value > axis->max ? axis->max - axis->min : + axis->value - axis->min) * len; x += (size_t)(axis->max - axis->min) / 2; x /= (size_t)(axis->max - axis->min); memmove(&buffer[x + sizeof("\033[m") - 1], &buffer[x], len + 1 - x); @@ -51,35 +74,70 @@ main(int argc, char *argv[]) const struct input_absinfo *absinfo; struct libgamepad_input_event event; struct libgamepad_device gamepad; - const char **button_names = NULL; - size_t max_button_name_len = 0; + const char **button_names; + size_t max_button_name_len; size_t len, x, y, i; struct winsize size; - size_t button_columns = 0; - size_t button_rows = 0; - size_t max_abs_axis_name_len = 0; - struct abs_axis *abs_axes = NULL; + size_t button_columns; + size_t button_rows; + size_t max_abs_axis_name_len; + struct abs_axis *abs_axes; char *buffer; ssize_t saxis_len; size_t axis_len, req_axis_len; - size_t max_max_len = 0, max_min_len = 0; + size_t max_max_len, max_min_len; ssize_t r; + struct pollfd pfd; + struct sigaction action; if (argc != 2) { fprintf(stderr, "Please provide the path to the subdevice as the only command line argument\n"); return 1; } - if (libgamepad_open_device(&gamepad, AT_FDCWD, argv[1], O_RDONLY)) { + if (libgamepad_open_device(&gamepad, AT_FDCWD, argv[1], O_RDONLY | O_NONBLOCK)) { perror("libgamepad_open_device"); return 1; } - if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size)) { - perror("TIOCGWINSZ"); + pfd.fd = gamepad.fd; + pfd.events = POLLIN; + pfd.revents = 0; + + memset(&action, 0, sizeof(action)); + action.sa_handler = sigwinch_handler; + if (sigaction(SIGWINCH, &action, NULL)) { + perror("sigaction"); + return 1; + } + + memset(&action, 0, sizeof(action)); + action.sa_handler = sigint_handler; + if (sigaction(SIGINT, &action, NULL)) { + perror("sigaction"); return 1; } +redraw: + button_names = NULL; + max_button_name_len = 0; + button_columns = 0; + button_rows = 0; + max_abs_axis_name_len = 0; + abs_axes = NULL; + max_max_len = 0; + max_min_len = 0; + + while (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size)) { + if (errno != EINTR) { + perror("TIOCGWINSZ"); + return 1; + } + sigwinch_received = 0; + if (sigint_received) + goto out; + } + size.ws_row = size.ws_row < 1 ? 1 : size.ws_row; size.ws_col = size.ws_col < 1 ? 1 : size.ws_col; @@ -151,11 +209,28 @@ main(int argc, char *argv[]) fflush(stdout); for (;;) { - /* TODO use nonblocking; listen for window resize */ + if (sigwinch_received) { + sigwinch_received = 0; + free(button_names); + free(abs_axes); + free(buffer); + goto redraw; + } + if (sigint_received) + break; + + if (poll(&pfd, 1, -1) < 0) { + if (errno == EINTR) + continue; + break; + } + r = libgamepad_next_event(&gamepad, &event, 1); if (r <= 0) { if (!r || errno == EINTR) continue; + if (errno == EAGAIN) + break; perror("libgamepad_next_event"); return 1; } @@ -179,5 +254,10 @@ main(int argc, char *argv[]) /* TODO add relative axis */ } +out: + free(buffer); + free(button_names); + free(abs_axes); + libgamepad_close_device(&gamepad); return 0; } |