/* $Id$ */ #include #include #include #define TEKHEIGHT 3072 #define TEKWIDTH 4096 #define FIVEBITS 037 #define HIBITS (FIVEBITS << SHIFTHI) #define LOBITS (FIVEBITS << SHIFTLO) #define SHIFTHI 7 #define SHIFTLO 2 #define TWOBITS 03 #undef GS #undef RS #undef US #define GS 0x001D #define RS 0x001E #define US 0x001F /* * Switch to/from tek4014/vt100 mode. */ static void tek_enable(int flag) { if (flag) do_csi("?38h"); else esc("\003"); } /* * Switch to GIN (graphics-in) mode. */ static void tek_GIN(void) { esc("\032"); } /* * Switch back to alpha (text) mode. */ static void tek_ALP(void) { printf("%c", US); } /* * Select a font */ static void tek_font(int code) { switch (code) { case 1: esc("8"); /* large */ break; case 2: esc("9"); /* #2 */ break; case 3: esc(":"); /* #3 */ break; default: esc(";"); /* small */ break; } } /* * Decode 2 bytes from a mouse report as a coordinate value. */ static int tek_coord(char *report, int offset) { int hi = FIVEBITS & CharOf(report[offset]); int lo = FIVEBITS & CharOf(report[offset + 1]); return (hi << 5) + lo; } /* * Send coordinates for a single point. xterm reads this info in getpoint(). * There are several possibilities for encoding the coordinates. */ static void tek_point(int pen, int y, int x) { char temp[20]; if (pen) { sprintf(temp, "%c\007", GS); } else { sprintf(temp, "%c", GS); } sprintf(temp + strlen(temp), "%c%c%c%c%c", 0x20 | (((y & HIBITS) >> SHIFTHI) & FIVEBITS), 0x60 | (((y & TWOBITS) << SHIFTLO) | (x & TWOBITS)), /* tests/sets lo_y */ 0x60 | (((y & LOBITS) >> SHIFTLO) & FIVEBITS), /* sets lo_y */ 0x20 | (((x & HIBITS) >> SHIFTHI) & FIVEBITS), 0x40 | (((x & LOBITS) >> SHIFTLO) & FIVEBITS)); /* must be last */ fprintf(stdout, "%s", temp); if (LOG_ENABLED) { fprintf(log_fp, "*Set point (%d,%d)\n", y, x); fputs("Send: ", log_fp); put_string(log_fp, temp); fputs("\n", log_fp); } } static void tek_linestyle(int style) { char temp[10]; sprintf(temp, "%c", 0x60 + style); esc(temp); } static void log_mouse_click(char *report) { if (LOG_ENABLED) { int new_x = tek_coord(report, 1); int new_y = tek_coord(report, 3); fprintf(log_fp, "Report: "); if ((report[0] & 0x80) != 0 && strchr("lmrLMR", report[0] & 0x7f) != 0) { fprintf(log_fp, "mouse %c", report[0] & 0x7f); } else { fprintf(log_fp, "key %d", CharOf(report[0])); } fprintf(log_fp, " (%d,%d)\n", new_y, new_x); fflush(log_fp); } } /* * Clear the display */ static int tek_clear(MENU_ARGS) { tek_enable(1); esc("\014"); tek_enable(0); return FALSE; } static int tek_hello(MENU_ARGS) { int n; tek_clear(PASS_ARGS); tek_enable(1); for (n = 0; n < 4; ++n) { tek_font(n); println("Hello world!\r"); } tek_enable(0); return FALSE; } /* * Wait for a mouse click, printing its coordinates. While in GIN mode, we * may also see keys pressed. Exit the test when we see the same event twice * in a row. */ static int tek_mouse_coords(MENU_ARGS) { char *report; char status[6]; int new_x = -1; int new_y = -1; tek_clear(PASS_ARGS); tek_enable(1); set_tty_raw(TRUE); set_tty_echo(FALSE); report = ""; println("Any key or mouse click twice to exit..."); do { strncpy(status, report, 5)[5] = 0; /* * The graphics-in mode is reset each time users send a mouse click. So we * set it in the loop. */ tek_GIN(); log_mouse_click(report = instr()); new_x = tek_coord(report, 1); new_y = tek_coord(report, 3); /* * If we do not start a new line after reading the mouse, we will see no * text. So we do it before the rest of the report rather than after. */ printf("\r\n"); if ((report[0] & 0x80) != 0 && strchr("lmrLMR", report[0] & 0x7f) != 0) { printf("mouse %c:", report[0] & 0x7f); } else { printf("key: %d", CharOf(report[0])); } printf(" (%d,%d)", new_y, new_x); fflush(stdout); } while (strcmp(report, status)); tek_ALP(); restore_ttymodes(); tek_enable(0); return FALSE; } /* * Wait for a mouse click, drawing a line point-to-point from each click. * Ignore keys pressed. Exit the test when we see the same event twice * in a row. * * xterm pretends the screen is 4096 by 3072 (height by width). So the lines * appear in the lower-right of the screen. Since we cannot ask xterm how * large the screen actually is, we do not try to (cannot) scale the lines. */ static int tek_mouse_lines(MENU_ARGS) { char *report; char status[6]; int old_x = -1; int old_y = -1; int new_x = -1; int new_y = -1; tek_clear(PASS_ARGS); tek_enable(1); set_tty_raw(TRUE); set_tty_echo(FALSE); report = ""; println("Any mouse click twice to exit..."); do { strncpy(status, report, 5)[5] = 0; if (old_x >= 0 && old_y >= 0) { tek_point(0, old_y, old_x); tek_point(1, new_y, new_x); fflush(stdout); } old_x = new_x; old_y = new_y; tek_GIN(); log_mouse_click(report = instr()); new_x = tek_coord(report, 1); new_y = tek_coord(report, 3); } while (strcmp(report, status)); restore_ttymodes(); tek_enable(0); return FALSE; } /* * Draw a grid using a different line-type for each line, if possible. */ static int tek_grid_demo(MENU_ARGS) { int y, x; int style = 0; tek_clear(PASS_ARGS); tek_enable(1); for (y = 0; y <= TEKHEIGHT; y += TEKHEIGHT / 16) { tek_linestyle(style++ % 4); tek_point(0, y, 0); tek_point(1, y, TEKWIDTH - 1); } for (x = 0; x <= TEKWIDTH; x += TEKWIDTH / 16) { tek_linestyle(style++ % 4); tek_point(0, 0, x); tek_point(1, TEKHEIGHT - 1, x); } tek_ALP(); /* flush the plot */ tek_enable(0); return FALSE; } /* * The common versions of xterm (X11R5, X11R6, XFree86) provide a Tektronix * 4014 emulation. It can be configured out of XFree86 xterm, but that fact is * ignored by the cretins who quote rxvt's misleading manpage. (The emulation * if unused accounts for 30kb of shared memory use). * * Other than its association with xterm, these tests do not really belong * in vttest, since the Tektronix is not even an ANSI terminal. */ int tst_tek4014(MENU_ARGS) { static MENU my_menu[] = { { "Exit", 0 }, { "Clear screen", tek_clear }, { "'Hello World!' in each font", tek_hello }, { "Get mouse-clicks, showing coordinates", tek_mouse_coords }, { "Get mouse-clicks, drawing lines between", tek_mouse_lines }, { "Draw a grid", tek_grid_demo }, { "", 0 } }; do { vt_clear(2); title(0); println("XTERM/tek4014 features"); title(2); println("Choose test type:"); } while (menu(my_menu)); return MENU_NOHOLD; }