aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libgamepad.h2
-rw-r--r--libgamepad_list_superdevices.c48
-rw-r--r--test-visual.c106
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;
}