Compare commits
18 Commits
e43e9ebeca
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
aa2f951ff4
|
|||
|
a3de2c367e
|
|||
|
a0953ef485
|
|||
|
bc685fb3f3
|
|||
|
a742f3d9d2
|
|||
|
5427dfb428
|
|||
|
92d6337561
|
|||
|
5331b49ed6
|
|||
|
632f88eeeb
|
|||
|
15b630ba30
|
|||
|
260f33dfb7
|
|||
|
745c16704a
|
|||
|
0c33532611
|
|||
|
3fcb2896cb
|
|||
|
de09819ff5
|
|||
|
7f7b725378
|
|||
|
15d0bd5bd6
|
|||
|
d2e40f9636
|
10
.clang-format
Normal file
10
.clang-format
Normal file
@@ -0,0 +1,10 @@
|
||||
BasedOnStyle: LLVM
|
||||
ColumnLimit: 80
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: ForContinuationAndIndentation
|
||||
SpaceAfterCStyleCast: true
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignOperands: DontAlign
|
||||
AlignConsecutiveMacros: Consecutive
|
||||
Cpp11BracedListStyle: false
|
||||
344
termtest.c
344
termtest.c
@@ -1,7 +1,7 @@
|
||||
//
|
||||
// termtest: terminal evaluation tool
|
||||
//
|
||||
// Copyright (c) 2020, Přemysl Eric Janouch <p@janouch.name>
|
||||
// Copyright (c) 2020 - 2021, Přemysl Eric Janouch <p@janouch.name>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted.
|
||||
@@ -17,24 +17,32 @@
|
||||
|
||||
// NOTE: We don't need to and will not free any memory. This is intentional.
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <glob.h>
|
||||
#include <poll.h>
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <curses.h>
|
||||
#include <term.h>
|
||||
|
||||
// tiparm is ncurses-specific, let's make this a tiny bit more portable.
|
||||
#define TIPARM(s, v1) tparm((s), (long) (v1))
|
||||
|
||||
#define CSI "\x1b["
|
||||
#define OSC "\x1b]"
|
||||
#define DCS "\x1bP"
|
||||
#define ST "\x1b\\"
|
||||
#define ST8 "\x9c"
|
||||
#define BEL "\x07"
|
||||
#define ST "\x9c"
|
||||
|
||||
#define SGR0 CSI "m"
|
||||
|
||||
extern char **environ;
|
||||
static struct termios saved_termios;
|
||||
@@ -68,15 +76,25 @@ static bool tty_cbreak() {
|
||||
// if it didn't manage to get a response, or when an error has happened.
|
||||
static char *comm(const char *req, bool wait_first) {
|
||||
ssize_t len = write(STDOUT_FILENO, req, strlen(req));
|
||||
if (len < strlen(req)) return NULL;
|
||||
if (len < strlen(req))
|
||||
return NULL;
|
||||
|
||||
char buf[1000] = ""; size_t buf_len = 0; int n = 0;
|
||||
struct pollfd pfd = { .fd = STDIN_FILENO, .events = POLLIN };
|
||||
if (wait_first) poll(&pfd, 1, -1);
|
||||
while ((n = poll(&pfd, 1, 50 /* unreliable, timing-dependent */))) {
|
||||
if (n < 0) return NULL;
|
||||
if (wait_first)
|
||||
poll(&pfd, 1, -1);
|
||||
|
||||
int lag = getenv("SSH_CONNECTION") ? 250 : 50;
|
||||
char buf[1000] = "";
|
||||
size_t buf_len = 0;
|
||||
int n = 0;
|
||||
while ((n = poll(&pfd, 1, lag /* unreliable, timing-dependent */))) {
|
||||
if (n < 0)
|
||||
return NULL;
|
||||
|
||||
len = read(STDIN_FILENO, buf + buf_len, sizeof buf - buf_len - 1);
|
||||
if (len <= 0) return NULL;
|
||||
if (len <= 0)
|
||||
return NULL;
|
||||
|
||||
buf_len += len;
|
||||
}
|
||||
return strdup(buf);
|
||||
@@ -86,29 +104,44 @@ enum { DEC_UNKNOWN, DEC_SET, DEC_RESET, DEC_PERMSET, DEC_PERMRESET };
|
||||
|
||||
// decrpmstr returns a textual description of a DECRPM response.
|
||||
static const char *decrpmstr(int status) {
|
||||
if (status == DEC_UNKNOWN) return "unknown";
|
||||
if (status == DEC_SET) return "set";
|
||||
if (status == DEC_RESET) return "reset";
|
||||
if (status == DEC_PERMSET) return "permanently set";
|
||||
if (status == DEC_PERMRESET) return "permanently reset";
|
||||
switch (status) {
|
||||
case DEC_UNKNOWN:
|
||||
return "unknown";
|
||||
case DEC_SET:
|
||||
return "set";
|
||||
case DEC_RESET:
|
||||
return "reset";
|
||||
case DEC_PERMSET:
|
||||
return "permanently set";
|
||||
case DEC_PERMRESET:
|
||||
return "permanently reset";
|
||||
default:
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
// parse_decrpm returns whether the mode response is valid (result >= 0),
|
||||
// as well as the terminal's response if it is, see the DEC_* constants.
|
||||
static int parse_decrpm(const char *resp) {
|
||||
// E.g., \x1b[?1000;2$y
|
||||
if (resp[0] != '\x1b' || resp[1] != '[' || resp[2] != '?') return -1;
|
||||
char *end = NULL; errno = 0; long mode = strtol(resp + 3, &end, 10);
|
||||
if (errno || mode < 0 || *end != ';') return -1;
|
||||
if (!isdigit(end[1]) || end[2] != '$' || end[3] != 'y' || end[4]) return -1;
|
||||
if (resp[0] != '\x1b' || resp[1] != '[' || resp[2] != '?')
|
||||
return -1;
|
||||
|
||||
char *end = NULL;
|
||||
errno = 0;
|
||||
long mode = strtol(resp + 3, &end, 10);
|
||||
if (errno || mode < 0 || *end != ';')
|
||||
return -1;
|
||||
if (!isdigit(end[1]) || end[2] != '$' || end[3] != 'y' || end[4])
|
||||
return -1;
|
||||
return end[1] - '0';
|
||||
}
|
||||
|
||||
// deccheck checks whether a particular DEC mode is supported, whether it is
|
||||
// enabled, and returns that information as a string.
|
||||
static const char *deccheck(int number) {
|
||||
char buf[1000] = ""; snprintf(buf, sizeof buf, CSI "?%d$p", number);
|
||||
char buf[1000] = "";
|
||||
snprintf(buf, sizeof buf, CSI "?%d$p", number);
|
||||
return decrpmstr(parse_decrpm(comm(buf, false)));
|
||||
}
|
||||
|
||||
@@ -124,18 +157,24 @@ static void test_mouse(int mode) {
|
||||
|
||||
unsigned int b = -1, x = -1, y = -1;
|
||||
unsigned char bc = -1, xc = -1, yc = -1, m = -1;
|
||||
if (sscanf(resp, CSI "M%c%c%c", &bc, &xc, &yc) == 3
|
||||
&& bc >= 32 && xc >= 32 && yc >= 32) {
|
||||
if (sscanf(resp, CSI "M%c%c%c", &bc, &xc, &yc) == 3 &&
|
||||
bc >= 32 && xc >= 32 && yc >= 32) {
|
||||
// Beware that this isn't compatible with xterm run with the -lc switch.
|
||||
if (strlen(resp) > 6) printf("1005\n");
|
||||
else printf("1000/1005 (%d @ %d,%d)\n", bc - 32, xc - 32, yc - 32);
|
||||
} else if (sscanf(resp, CSI "<%u;%u;%u%c", &b, &x, &y, &m) == 4
|
||||
&& (m == 'm' || m == 'M')) {
|
||||
if (strlen(resp) > 6) {
|
||||
printf("1005? ");
|
||||
for (const char *p = resp; *p; p++)
|
||||
printf("%c", *p < 32 || *p > 127 ? '.' : *p);
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("1000/1005 (%d @ %d,%d)\n", bc - 32, xc - 32, yc - 32);
|
||||
}
|
||||
} else if (sscanf(resp, CSI "<%u;%u;%u%c", &b, &x, &y, &m) == 4 &&
|
||||
(m == 'm' || m == 'M')) {
|
||||
printf("%s (%u%c @ %u,%u)\n",
|
||||
(x > ws.ws_col || y > ws.ws_row) ? "1016" : "1006/1016",
|
||||
b, m, x, y);
|
||||
} else if (sscanf(resp, CSI "%u;%u;%u%c", &b, &x, &y, &m) == 4
|
||||
&& m == 'M') {
|
||||
} else if (sscanf(resp, CSI "%u;%u;%u%c", &b, &x, &y, &m) == 4 &&
|
||||
m == 'M') {
|
||||
printf("1015 (%u @ %u,%u)\n", b - 32, x, y);
|
||||
} else {
|
||||
printf("Failed to parse.\n");
|
||||
@@ -144,6 +183,27 @@ static void test_mouse(int mode) {
|
||||
comm("Waiting for button up events, press a key if hanging.\n", true);
|
||||
}
|
||||
|
||||
// parse_decrpss checks a DECRPSS sequence and cuts out the inner part.
|
||||
// Returns NULL if it fails to validate.
|
||||
static char *parse_decrpss(char *resp) {
|
||||
if (strncmp(resp, DCS "1$r", 5))
|
||||
return NULL;
|
||||
|
||||
*strpbrk(resp + 5, BEL ST8 "\x1b") = 0;
|
||||
return resp + 5;
|
||||
}
|
||||
|
||||
// colour prints a cell with the given indexed colour as a background.
|
||||
static void colour(int n) {
|
||||
n > 7 ? printf(CSI "48;5;%dm ", n) : printf(CSI "%dm ", 40 + n);
|
||||
}
|
||||
|
||||
// direct prints a cell with the given direct colour as a background.
|
||||
// sep can be set either to ':' for ISO-8613-6 or ';' for more compatibility.
|
||||
static void direct(char sep, int r, int g, int b) {
|
||||
printf(CSI "48%c2%c%d%c%d%c%dm ", sep, sep, r, sep, g, sep, b);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (!tty_cbreak())
|
||||
abort();
|
||||
@@ -154,8 +214,9 @@ int main(int argc, char *argv[]) {
|
||||
printf("\n");
|
||||
|
||||
// Initialise terminfo, this should definitely succeed.
|
||||
int err; char *term = getenv("TERM");
|
||||
if (setupterm((char *)term, 1, &err) != OK)
|
||||
int err;
|
||||
char *term = getenv("TERM");
|
||||
if (setupterm((char *) term, 1, &err) != OK)
|
||||
abort();
|
||||
|
||||
// VTE wouldn't have sent a response to DECRQM otherwise!
|
||||
@@ -177,6 +238,10 @@ int main(int argc, char *argv[]) {
|
||||
printf("%d\n", decrqm_supported);
|
||||
|
||||
printf("-- Colours\n");
|
||||
start_color(); // Does this need initscr()? ncurses doesn't initialise.
|
||||
printf("Terminfo: %d colours, has_colors=%d\n",
|
||||
tigetnum("colors"), has_colors());
|
||||
|
||||
char *colorterm = getenv("COLORTERM");
|
||||
if (colorterm) {
|
||||
printf("COLORTERM=%s", colorterm);
|
||||
@@ -185,47 +250,104 @@ int main(int argc, char *argv[]) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// See tmux(1), TERMINFO EXTENSIONS. These are somewhat unusual,
|
||||
// including them out of curiosity.
|
||||
// For a comprehensive list of unusual terminfo entries, see tmux(1),
|
||||
// user_caps(5), and comments in misc/terminfo.src. Looking for them
|
||||
// here out of curiosity, all sequences are mostly standardised.
|
||||
const char *Tc = tigetstr("Tc");
|
||||
if (Tc && Tc != (char *)-1)
|
||||
if (Tc && Tc != (char *) -1)
|
||||
printf("Terminfo: tmux extension claims direct color.\n");
|
||||
|
||||
// TODO:
|
||||
// - terminfo
|
||||
// - hardcoded visual check
|
||||
// Check the confusion, see https://gist.github.com/XVilka/8346728
|
||||
char *sgr5_semi =
|
||||
parse_decrpss(comm(CSI "48;5;160m" DCS "$qm" ST "\r", false));
|
||||
char *sgr5_colon =
|
||||
parse_decrpss(comm(CSI "48:5:161m" DCS "$qm" ST "\r", false));
|
||||
char *sgr2_colon =
|
||||
parse_decrpss(comm(CSI "48:2::255:0:0m" DCS "$qm" ST "\r", false));
|
||||
char *sgr2_double =
|
||||
parse_decrpss(comm(CSI "48:2::0:255:0m" DCS "$qm" ST "\r", false));
|
||||
comm(SGR0, false);
|
||||
|
||||
if (sgr5_semi)
|
||||
printf("SGR 160, semicolon: %s\n", sgr5_semi);
|
||||
if (sgr5_colon)
|
||||
printf("SGR 161, colon: %s\n", sgr5_colon);
|
||||
if (sgr2_colon)
|
||||
printf("SGR #ff0000, colon: %s\n", sgr2_colon);
|
||||
if (sgr2_double)
|
||||
printf("SGR #00ff00, double colon: %s\n", sgr2_double);
|
||||
|
||||
for (int n = 0; n < 8; n++) colour(n); printf(SGR0 "\n");
|
||||
for (int n = 8; n < 16; n++) colour(n); printf(SGR0 "\n");
|
||||
for (int n = 232; n < 256; n++) colour(n); printf(SGR0 "\n");
|
||||
|
||||
// Ideally, both ramps should be visible, and smooth.
|
||||
for (int g = 255; g >= 192; g--) direct(';', 255, g, 0); printf(SGR0 "\n");
|
||||
for (int g = 255; g >= 192; g--) direct(':', 255, g, 0); printf(SGR0 "\n");
|
||||
|
||||
printf("-- Colour change\n");
|
||||
// TODO:
|
||||
// - terminfo
|
||||
// - hardcoded visual check
|
||||
// - see acolors.sh from xterm's vttests, it changes terminal colours
|
||||
// (and urxvt passed that, at least apparently)
|
||||
printf("Terminfo: can_change %d, initialize_color %d\n",
|
||||
!!can_change, !!initialize_color);
|
||||
|
||||
printf("-- Blink attribute\n");
|
||||
bool bbc_supported = enter_bold_mode && enter_blink_mode
|
||||
&& set_a_foreground && set_a_background && exit_attribute_mode;
|
||||
// The response from urxvt is wrongly missing the colour number.
|
||||
char *bright_red_save = comm(OSC "4;9;?" BEL, false);
|
||||
if (!strncmp(bright_red_save, OSC "4;", 4)) {
|
||||
char *copy = strdup(bright_red_save + 4);
|
||||
*strpbrk(copy, BEL ST8 "\x1b") = 0;
|
||||
printf("We have read colour contents from the terminal: %s\n", copy);
|
||||
} else
|
||||
*bright_red_save = 0;
|
||||
|
||||
printf(CSI "0;38;5;9m" "Indexed" SGR0 " " CSI "1;31m" "Bold" SGR0 "\n");
|
||||
printf("Press a key to stop.\n");
|
||||
for (int r = 0; r < 255; r += 8) {
|
||||
char buf[1000] = "";
|
||||
snprintf(buf, sizeof buf, OSC "4;9;rgb:%02x/%02x/%02x" BEL, r, 0, 0);
|
||||
if (*comm(buf, false))
|
||||
break;
|
||||
|
||||
poll(NULL, 0, 50 /* delay */);
|
||||
}
|
||||
if (*bright_red_save)
|
||||
comm(bright_red_save, false);
|
||||
else
|
||||
comm(OSC "104;9" BEL, false);
|
||||
|
||||
// Linux palette sequence, supported by e.g. pterm.
|
||||
for (int r = 0; r < 255; r += 8) {
|
||||
char buf[1000] = "";
|
||||
snprintf(buf, sizeof buf, OSC "P9%02x%02x%02x", r, 0, 0);
|
||||
if (*comm(buf, false))
|
||||
break;
|
||||
|
||||
poll(NULL, 0, 50 /* delay */);
|
||||
}
|
||||
comm("\a\r", false); // Take care of unsupporting terminals.
|
||||
|
||||
printf("-- Bold and blink attributes\n");
|
||||
bool bbc_supported = enter_bold_mode && enter_blink_mode &&
|
||||
set_a_foreground && set_a_background && exit_attribute_mode;
|
||||
printf("Terminfo: %d\n", bbc_supported);
|
||||
if (bbc_supported) {
|
||||
tputs(tiparm(set_a_foreground, COLOR_GREEN), 1, putchar);
|
||||
tputs(tiparm(set_a_background, COLOR_BLUE), 1, putchar);
|
||||
tputs(TIPARM(set_a_foreground, COLOR_GREEN), 1, putchar);
|
||||
tputs(TIPARM(set_a_background, COLOR_BLUE), 1, putchar);
|
||||
printf("Terminfo%s ", exit_attribute_mode);
|
||||
tputs(enter_bold_mode, 1, putchar);
|
||||
tputs(tiparm(set_a_foreground, COLOR_GREEN), 1, putchar);
|
||||
tputs(tiparm(set_a_background, COLOR_BLUE), 1, putchar);
|
||||
tputs(TIPARM(set_a_foreground, COLOR_GREEN), 1, putchar);
|
||||
tputs(TIPARM(set_a_background, COLOR_BLUE), 1, putchar);
|
||||
printf("Bold%s ", exit_attribute_mode);
|
||||
tputs(enter_blink_mode, 1, putchar);
|
||||
tputs(tiparm(set_a_foreground, COLOR_GREEN), 1, putchar);
|
||||
tputs(tiparm(set_a_background, COLOR_BLUE), 1, putchar);
|
||||
tputs(TIPARM(set_a_foreground, COLOR_GREEN), 1, putchar);
|
||||
tputs(TIPARM(set_a_background, COLOR_BLUE), 1, putchar);
|
||||
printf("Blink%s ", exit_attribute_mode);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf(CSI "0;32;44m" "SGR" CSI "m ");
|
||||
printf(CSI "1;32;44m" "Bold" CSI "m ");
|
||||
printf(CSI "5;32;44m" "Blink" CSI "m ");
|
||||
printf(CSI "0;32;44m" "SGR" SGR0 " ");
|
||||
printf(CSI "1;32;44m" "Bold" SGR0 " ");
|
||||
printf(CSI "5;32;44m" "Blink" SGR0 " ");
|
||||
printf("\n");
|
||||
printf(CSI "0;5m" "Blink with default colours." CSI "m");
|
||||
printf(CSI "0;5m" "Blink with default colours." SGR0);
|
||||
printf("\n");
|
||||
|
||||
printf("-- Italic attribute\n");
|
||||
@@ -233,52 +355,92 @@ int main(int argc, char *argv[]) {
|
||||
printf("Terminfo: %d\n", italic_supported);
|
||||
if (italic_supported)
|
||||
printf("%sTerminfo test.%s\n", enter_italics_mode, exit_italics_mode);
|
||||
printf(CSI "3m" "SGR test.\n" CSI "0m");
|
||||
printf(CSI "3m" "SGR test.\n" SGR0);
|
||||
|
||||
printf("-- Overline attribute\n");
|
||||
const char *Smol = tigetstr("Smol");
|
||||
if (Smol && Smol != (char *) -1)
|
||||
printf("Terminfo: found tmux extension.\n");
|
||||
printf(CSI "53m" "SGR test.\n" SGR0);
|
||||
|
||||
printf("-- Underline colour\n");
|
||||
const char *setal = tigetstr("setal");
|
||||
const char *ol = tigetstr("ol");
|
||||
if (setal && setal != (char *) -1 && ol && ol != (char *) -1)
|
||||
printf("Terminfo: found mintty extension.\n");
|
||||
const char *Setulc = tigetstr("Setulc");
|
||||
if (Setulc && Setulc != (char *) -1)
|
||||
printf("Terminfo: found tmux extension.\n");
|
||||
printf(CSI "4;58;2;0;255;0m" "SGR test." SGR0 "\n");
|
||||
printf(CSI "4;58:5:46m" "SGR test." SGR0 "\n");
|
||||
|
||||
printf("-- Bar cursor\n");
|
||||
const char *Ss = tigetstr("Ss");
|
||||
const char *Se = tigetstr("Se");
|
||||
if (Ss && Ss != (char*)-1)
|
||||
if (Ss && Ss != (char *) -1)
|
||||
printf("Terminfo: found tmux extension for setting.\n");
|
||||
if (Se && Se != (char*)-1)
|
||||
if (Se && Se != (char *) -1)
|
||||
printf("Terminfo: found tmux extension for resetting.\n");
|
||||
if (parse_decrpss(comm(DCS "$q q" ST "\r", false)))
|
||||
printf("DECRQSS told us about cursor appearance!\n");
|
||||
|
||||
comm(CSI "5 q" "Blinking (press a key): ", true);
|
||||
printf("\n");
|
||||
comm(CSI "6 q" "Steady (press a key): ", true);
|
||||
printf("\n");
|
||||
|
||||
// There's no actual way of restoring this to what it was before.
|
||||
// There's no widely supported way of restoring this to what it was before.
|
||||
// Terminfo "cnorm" at most undoes blinking in xterm.
|
||||
comm(CSI "2 q", false);
|
||||
|
||||
printf("-- w3mimgdisplay\n");
|
||||
const char *windowid = getenv("WINDOWID");
|
||||
if (windowid) {
|
||||
printf("WINDOWID=%s\n", windowid);
|
||||
printf("There should be a picture. Press a key.\n");
|
||||
poll(NULL, 0, 50 /* wait for a refresh */);
|
||||
|
||||
char buf[1000] = "";
|
||||
snprintf(buf, sizeof buf, "/usr/lib/w3m:%s", getenv("PATH"));
|
||||
setenv("PATH", buf, true /* replace */);
|
||||
|
||||
// TODO:
|
||||
// - run w3mimgdisplay now, hardcoded visual check
|
||||
// - I guess I'll need a picture to show
|
||||
// - /usr/share/pixmaps/debian-logo.png
|
||||
// - /usr/share/icons/HighContrast/48x48/stock/gtk-yes.png
|
||||
// - we get run from a relative path, so not sure about local
|
||||
// - or we can create our own picture, something easily compressible
|
||||
// - can even pass that as an fd during fork and use /dev/fd/N
|
||||
glob_t gb;
|
||||
glob("/usr/share/pixmaps/*.xpm", 0, NULL, &gb);
|
||||
glob("/usr/share/pixmaps/*.png", GLOB_APPEND, NULL, &gb);
|
||||
|
||||
FILE *fp = popen("w3mimgdisplay >/dev/null", "w");
|
||||
fprintf(fp, "0;1;0;0;%d;%d;;;;;%s\n4;\n3;", 100, 100, gb.gl_pathv[0]);
|
||||
pclose(fp);
|
||||
globfree(&gb);
|
||||
|
||||
comm("", true);
|
||||
}
|
||||
|
||||
printf("-- Sixel graphics\n");
|
||||
// TODO:
|
||||
// - hardcoded visual check
|
||||
char *da1 = comm(CSI "c", false);
|
||||
if (!strncmp(da1, CSI "?", 3)) {
|
||||
char *p = da1 + 3, *end = p;
|
||||
long mode;
|
||||
while ((mode = strtol(p, &end, 10)) && (*end == ';' || *end == 'c')) {
|
||||
if (mode == 4)
|
||||
printf("DA1: the terminal claims to support Sixel graphics.\n");
|
||||
p = end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
comm(CSI "4c" DCS "0;0;0;q??~~??~~??iTiTiT" ST, false);
|
||||
|
||||
printf("-- Mouse protocol\n");
|
||||
printf("Maximise the terminal window and click the rightmost column.\n");
|
||||
// TODO: Bug the user into resizing it wide enough, or at least making
|
||||
// the font smaller. Or maybe just warn, and say how many columns there
|
||||
// need to be (255 - 32 + 1 = 224).
|
||||
// TODO: Inspect terminfo kmous, XM, xm.
|
||||
// - We can say what protocol kmous expects, whether 1000 or 1006.
|
||||
// - Sadly urxvt still has the 1000/1005 sequence there.
|
||||
while (!ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) && ws.ws_col < 223) {
|
||||
if (!*comm("Your terminal needs to be at least 223 columns wide.\n"
|
||||
"Press a key once you've made it wide enough.\n", true))
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Click the rightmost column, if it's possible.\n");
|
||||
int mouses[] = { 1005, 1006, 1015, 1016 };
|
||||
for (size_t i = 0; i < sizeof mouses / sizeof *mouses; i++) {
|
||||
if (decrqm_supported)
|
||||
@@ -287,19 +449,39 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
comm(CSI "?1000l", false);
|
||||
|
||||
printf("-- Focus events\n");
|
||||
const char *Dsfcs = tigetstr("Dsfcs");
|
||||
const char *Enfcs = tigetstr("Enfcs");
|
||||
if (Dsfcs && Dsfcs != (char *) -1 && Enfcs && Enfcs != (char *) -1)
|
||||
printf("Terminfo: found tmux extension.\n");
|
||||
if (decrqm_supported)
|
||||
printf("DECRQM: %s\n", deccheck(1004));
|
||||
comm(CSI "?1000h" CSI "?1004h", false);
|
||||
printf("Focus in and out of the window, press a key to abort.\n");
|
||||
while (true) {
|
||||
char *in = comm("", true);
|
||||
if (*in != '\x1b')
|
||||
break;
|
||||
else if (in[1] == '[' && in[2] == 'I')
|
||||
printf("Focused in.\n");
|
||||
else if (in[1] == '[' && in[2] == 'O')
|
||||
printf("Focused out.\n");
|
||||
}
|
||||
comm(CSI "?1000l" CSI "?1004l", false);
|
||||
|
||||
printf("-- Selection\n");
|
||||
const char *Ms = tigetstr("Ms");
|
||||
if (Ms && Ms != (char *)-1)
|
||||
printf("Terminfo: found tmux extension for selections.\n");
|
||||
if (Ms && Ms != (char *) -1)
|
||||
printf("Terminfo: found tmux extension.\n");
|
||||
|
||||
char *selection = comm(OSC "52;pc;?" BEL, false);
|
||||
if (!strncmp(selection, OSC "52;", 5)) {
|
||||
printf("We have received the selection from the terminal!" CSI "1m\n");
|
||||
char *semi = strrchr(selection, ';');
|
||||
*strpbrk(semi, BEL ST) = 0;
|
||||
*strpbrk(semi, BEL ST8 "\x1b") = 0;
|
||||
FILE *fp = popen("base64 -d", "w");
|
||||
fprintf(fp, "%s", semi + 1);
|
||||
fclose(fp);
|
||||
pclose(fp);
|
||||
printf(CSI "m\n");
|
||||
}
|
||||
|
||||
@@ -307,6 +489,10 @@ int main(int argc, char *argv[]) {
|
||||
comm("Check if the selection now contains 'Test' and press a key.\n", true);
|
||||
|
||||
printf("-- Bracketed paste\n");
|
||||
const char *Dsbp = tigetstr("Dsbp");
|
||||
const char *Enbp = tigetstr("Enbp");
|
||||
if (Dsbp && Dsbp != (char *) -1 && Enbp && Enbp != (char *) -1)
|
||||
printf("Terminfo: found tmux extension.\n");
|
||||
if (decrqm_supported)
|
||||
printf("DECRQM: %s\n", deccheck(2004));
|
||||
|
||||
@@ -314,10 +500,10 @@ int main(int argc, char *argv[]) {
|
||||
// so we'd have to use Xlib, and that is too much effort.
|
||||
char *pasted = comm(CSI "?2004h" "Paste something: ", true);
|
||||
printf("%d\n", !strncmp(pasted, CSI "200~", 6));
|
||||
comm(CSI "?2004l", false);
|
||||
|
||||
// Let the user see the results when run outside an interactive shell.
|
||||
comm("-- Finished\n", true);
|
||||
// TODO: Look further than tmux(1) for unusual terminfo entries.
|
||||
|
||||
// atexit is broken in tcc -run, see https://savannah.nongnu.org/bugs/?56495
|
||||
tty_atexit();
|
||||
|
||||
Reference in New Issue
Block a user