/* * Copyright (C) 2003 Red Hat, Inc. * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include "caps.hh" #if __has_include() #include #endif enum { tracking_x10 = 9, tracking_mouse = 1000, tracking_hilite = 1001, tracking_cell_motion = 1002, tracking_all_motion = 1003, tracking_focus = 1004, tracking_xterm_ext = 1006, }; static int tracking_mode = 0; static gboolean tracking_focus_mode = FALSE; static void decset(int mode, gboolean value) { fprintf(stdout, _VTE_CAP_CSI "?%d%c", mode, value ? 'h' : 'l'); } static void reset_mouse_tracking_mode(void) { decset(tracking_x10, FALSE); decset(tracking_mouse, FALSE); decset(tracking_hilite, FALSE); decset(tracking_cell_motion, FALSE); decset(tracking_all_motion, FALSE); decset(tracking_xterm_ext, FALSE); fflush(stdout); } static void reset(void) { reset_mouse_tracking_mode(); decset(tracking_focus, FALSE); fflush(stdout); } static void clear(void) { fprintf(stdout, "%s", _VTE_CAP_ESC "7" _VTE_CAP_CSI "11;1H" _VTE_CAP_CSI "1J" _VTE_CAP_CSI "2K" _VTE_CAP_CSI "1;1H"); reset_mouse_tracking_mode(); switch (tracking_mode) { case tracking_x10: fprintf(stdout, "X10 tracking enabled.\r\n"); decset(tracking_x10, TRUE); break; case tracking_mouse: fprintf(stdout, "Mouse tracking enabled.\r\n"); decset(tracking_mouse, TRUE); break; case tracking_hilite: fprintf(stdout, "Hilite tracking enabled.\r\n"); decset(tracking_hilite, TRUE); break; case tracking_cell_motion: fprintf(stdout, "Cell motion tracking enabled.\r\n"); decset(tracking_cell_motion, TRUE); break; case tracking_all_motion: fprintf(stdout, "All motion tracking enabled.\r\n"); decset(tracking_all_motion, TRUE); break; case tracking_xterm_ext: fprintf(stdout, "Xterm 1006 mouse tracking extension enabled.\r\n"); decset(tracking_xterm_ext, TRUE); break; default: fprintf(stdout, "Tracking disabled.\r\n"); break; } fprintf(stdout, "Tracking focus %s.\r\n", tracking_focus_mode ? "enabled":"disabled"); fprintf(stdout, "A - X10.\r\n"); fprintf(stdout, "B - Mouse tracking.\r\n"); fprintf(stdout, "C - Hilite tracking [FIXME: NOT IMPLEMENTED].\r\n"); fprintf(stdout, "D - Cell motion tracking.\r\n"); fprintf(stdout, "E - All motion tracking.\r\n"); fprintf(stdout, "F - Xterm 1006 extension.\r\n"); fprintf(stdout, "I - Focus tracking.\r\n"); fprintf(stdout, "Q - Quit.\r\n"); fprintf(stdout, "%s", _VTE_CAP_ESC "8"); fflush(stdout); } static gsize parse_legacy_mouse_mode(guint8 *data, gsize len) { int button = 0; const char *shift = "", *control = "", *alt = ""; gboolean motion = FALSE; int x, y; guint8 b; if (len < 6) return 0; b = data[3] - 32; switch (b & 3) { case 0: button = 1; if (b & 64) { button += 3; } break; case 1: button = 2; if (b & 64) { button += 3; } break; case 2: button = 3; if (b & 64) { button += 3; } break; case 3: button = 0; break; } shift = b & 4 ? "[shift]" : ""; alt = b & 8 ? "[alt]" : ""; control = b & 16 ? "[control]" : ""; motion = (b & 32) != 0; x = data[4] - 32; y = data[5] - 32; fprintf(stdout, "%d %s%s%s(%s%s%s) at %d,%d\r\n", button, motion ? "motion " : "", (!motion && button) ? "press" : "", (!motion && !button) ? "release" : "", alt, control, shift, x, y); return 6; } static gsize parse_esc(guint8 *data, gsize len) { if (len < 3) return 0; if (!(data[0] == '\033' && data[1] == '[')) /* CSI ? */ return 0; if (data[2] == 'M') return parse_legacy_mouse_mode(data, len); /* FIXME: add support for xterm extended mode (1006) */ if (data[2] == 'I' || data[2] == 'O') { fprintf(stdout, "focus %s\r\n", data[2] == 'I' ? "in" : "out"); return 3; } return 0; } static gsize print_data(guint8 *data, gsize len) { static const char codes[][6] = { "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI", "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US", "SPACE" }; gsize i; if (len == 0) return 0; for (i = 0; i < len; i++) { guint8 c = (guint8)data[i]; if (c == '\033' /* ESC */) { switch (data[++i]) { case '_': fprintf(stdout, "APC "); break; case '[': fprintf(stdout, "CSI "); break; case 'P': fprintf(stdout, "DCS "); break; case ']': fprintf(stdout, "OSC "); break; case '^': fprintf(stdout, "PM "); break; case '\\': fprintf(stdout, "ST "); break; default: fprintf(stdout, "ESC "); i--; break; } } else if (c <= 0x20) fprintf(stdout, "%s ", codes[c]); else if (c == 0x7f) fprintf(stdout, "DEL "); else if (c >= 0x80) fprintf(stdout, "\\%02x ", c); else fprintf(stdout, "%c ", c); } return len; } static gboolean parse(void) { GByteArray *bytes; guchar buffer[64]; gsize i, length; gboolean ret = FALSE; bytes = g_byte_array_new(); if ((length = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) { g_byte_array_append(bytes, buffer, length); } i = 0; while (i < bytes->len) { switch (bytes->data[i]) { case 'A': case 'a': tracking_mode = (tracking_mode == tracking_x10) ? 0 : tracking_x10; i++; break; case 'B': case 'b': tracking_mode = (tracking_mode == tracking_mouse) ? 0 : tracking_mouse; i++; break; case 'C': case 'c': tracking_mode = (tracking_mode == tracking_hilite) ? 0 : tracking_hilite; i++; break; case 'D': case 'd': tracking_mode = (tracking_mode == tracking_cell_motion) ? 0 : tracking_cell_motion; i++; break; case 'E': case 'e': tracking_mode = (tracking_mode == tracking_all_motion) ? 0 : tracking_all_motion; i++; break; case 'F': case 'f': tracking_mode = (tracking_mode == tracking_xterm_ext) ? 0 : tracking_xterm_ext; i++; break; case 'I': case 'i': tracking_focus_mode = !tracking_focus_mode; decset(tracking_focus, tracking_focus_mode); i++; break; case 'Q': case 'q': ret = TRUE; i++; break; case '\033': { gsize consumed = parse_esc(&bytes->data[i], bytes->len - i); if (consumed > 0) { i += consumed; break; } } /* fallthrough */ default: i += print_data(&bytes->data[i], bytes->len - i); fprintf(stdout, "\r\n"); break; } } fflush(stdout); g_byte_array_free(bytes, TRUE); return ret; } static struct termios tcattr, original; G_GNUC_NORETURN static void sigint_handler(int signum) { if (tcsetattr(STDIN_FILENO, TCSANOW, &original) != 0) { perror("tcsetattr"); } reset(); _exit(1); } int main(int argc, char **argv) { int flags; gboolean stop; fd_set in_fds; if (tcgetattr(STDIN_FILENO, &tcattr) != 0) { perror("tcgetattr"); return 1; } original = tcattr; signal(SIGINT, sigint_handler); cfmakeraw(&tcattr); if (tcsetattr(STDIN_FILENO, TCSANOW, &tcattr) != 0) { perror("tcsetattr"); return 1; } flags = fcntl(STDIN_FILENO, F_GETFL); fcntl(STDIN_FILENO, F_SETFL, flags & ~(O_NONBLOCK)); fprintf(stdout, "%s", _VTE_CAP_CSI "12;1H" _VTE_CAP_CSI "2K" _VTE_CAP_CSI "2J"); do { clear(); FD_ZERO(&in_fds); FD_SET(STDIN_FILENO, &in_fds); stop = TRUE; switch (select(STDIN_FILENO + 1, &in_fds, NULL, NULL, NULL)) { case 1: stop = parse(); break; default: stop = TRUE; break; } } while (!stop); reset(); fcntl(STDIN_FILENO, F_SETFL, flags); if (tcsetattr(STDIN_FILENO, TCSANOW, &original) != 0) { perror("tcsetattr"); return 1; } return 0; }