From 85d14178aedd73bc9d4f5c79b32881dd2b307de6 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 24 Jul 2022 21:22:10 +0200 Subject: Add test-visual MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- test-visual.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 test-visual.c (limited to 'test-visual.c') diff --git a/test-visual.c b/test-visual.c new file mode 100644 index 0000000..58ba20d --- /dev/null +++ b/test-visual.c @@ -0,0 +1,174 @@ +/* See LICENSE file for copyright and license details. */ +#include "libgamepad.h" + +#include +#include +#include +#include +#include +#include + + +struct abs_axis { + intmax_t min; + intmax_t max; + intmax_t value; + size_t max_len; + size_t min_len; +}; + + +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; + sprintf(buffer, "%-*ji%ji", (int)(len - axis->max_len), axis->min, axis->max); + width = len - axis->max_len - axis->min_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 = ((axis->value - axis->min) * len + (axis->max - axis->min) / 2) / (axis->max - axis->min); + memmove(&buffer[x + sizeof("\033[m") - 1], &buffer[x], len - x); + memcpy(&buffer[x], "\033[m", sizeof("\033[m") - 1); + return buffer; +} + + +int +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; + 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; + char *buffer; + ssize_t saxis_len; + size_t axis_len, req_axis_len; + size_t max_max_len = 0, max_min_len = 0; + int r; + + 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)) { + perror("libgamepad_open_device"); + return 1; + } + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &size)) { + perror("TIOCGWINSZ"); + return 1; + } + + size.ws_row = size.ws_row < 1 ? 1 : size.ws_row; + size.ws_col = size.ws_col < 1 ? 1 : size.ws_col; + + if (gamepad.nbuttons) { + button_names = calloc(gamepad.nbuttons, sizeof(*button_names)); + if (!button_names) { + perror("calloc"); + return 1; + } + for (i = 0; i < gamepad.nbuttons; i++) { + button_names[i] = libgamepad_get_button_name(gamepad.buttons[i]); + len = strlen(button_names[i]); + max_button_name_len = max_button_name_len > len ? max_button_name_len : len; + } + button_columns = (size.ws_col + 1) / (max_button_name_len + 3); + button_columns = button_columns < 1 ? 1 : button_columns; + button_rows = (gamepad.nbuttons + button_columns - 1) / button_columns; + } + + if (gamepad.nabsolute_axes) { + abs_axes = calloc(gamepad.nabsolute_axes, sizeof(*abs_axes)); + if (!abs_axes) { + perror("calloc"); + return 1; + } + for (i = 0; i < gamepad.nabsolute_axes; i++) { + len = strlen(libgamepad_get_absolute_axis_name(gamepad.absolute_axes[i])); + max_abs_axis_name_len = max_abs_axis_name_len > len ? max_abs_axis_name_len : len; + absinfo = libgamepad_get_absolute_axis_info(&gamepad, gamepad.absolute_axes[i]); + assert(absinfo); + abs_axes[i].min = (intmax_t)absinfo->minimum; + abs_axes[i].max = (intmax_t)absinfo->maximum; + abs_axes[i].value = (intmax_t)absinfo->value; + abs_axes[i].min_len = (size_t)snprintf(NULL, 0, "%ji", abs_axes[i].min); + max_min_len = max_min_len > abs_axes[i].min_len ? max_min_len : abs_axes[i].min_len; + abs_axes[i].max_len = (size_t)snprintf(NULL, 0, "%ji", abs_axes[i].max); + max_max_len = max_max_len > abs_axes[i].max_len ? max_max_len : abs_axes[i].max_len; + } + } + + req_axis_len = max_max_len + max_min_len + 2; + req_axis_len += max_max_len > max_min_len ? max_max_len : max_min_len; + saxis_len = (ssize_t)size.ws_col - (ssize_t)max_abs_axis_name_len - 3; + if (saxis_len < (ssize_t)req_axis_len) + saxis_len = (ssize_t)req_axis_len; + axis_len = (size_t)saxis_len; + buffer = malloc(axis_len + sizeof("\033[m")); + if (!buffer) { + perror("malloc"); + return 1; + } + + printf("\033[m\033[H\033[J\033[?25l"); + + for (i = 0; i < gamepad.nbuttons; i++) { + x = i % button_columns; + y = i / button_columns; + printf("\033[%zu;%zuH%s¿%s?\033[m", y + 1, x * (max_button_name_len + 3) + 1, + libgamepad_get_button_is_pressed(&gamepad, (unsigned int)gamepad.buttons[i]) ? "\033[7m" : "\033[m", + button_names[i]); + } + printf("\033[%zuH", button_rows + 1); + for (i = 0; i < gamepad.nabsolute_axes; i++) { + printf("\n%-*s ¿\033[7m%s?", (int)max_abs_axis_name_len, + libgamepad_get_absolute_axis_name((unsigned int)gamepad.absolute_axes[i]), + draw_axis(buffer, &abs_axes[i], axis_len)); + } + + fflush(stdout); + + for (;;) { + /* TODO use nonblocking; listen for window resize */ + r = libgamepad_next_event(&gamepad, &event); + if (r <= 0) { + if (!r || errno == EINTR) + continue; + perror("libgamepad_next_event"); + return 1; + } + + if (event.type == LIBGAMEPAD_BUTTON) { + i = (size_t)gamepad.button_map[event.code]; + x = i % button_columns; + y = i / button_columns; + printf("\033[%zu;%zuH%s[%s]\033[m", y + 1, x * (max_button_name_len + 3) + 1, + event.value ? "\033[7m" : "\033[m", button_names[i]); + fflush(stdout); + + } else if (event.type == LIBGAMEPAD_ABSOLUTE_AXIS) { + i = (size_t)gamepad.absolute_axis_map[event.code]; + y = button_rows + 1 + i; + x = max_abs_axis_name_len + 1; + abs_axes[i].value = (intmax_t)event.value; + printf("\033[%zu;%zuH[\033[7m%s]", y + 1, x + 1, draw_axis(buffer, &abs_axes[i], axis_len)); + fflush(stdout); + } + /* TODO add relative axis */ + } + + return 0; +} -- cgit v1.2.3-70-g09d2