📄 ncurses.c
字号:
/**************************************************************************** * Copyright (c) 1998-2003,2004 Free Software Foundation, Inc. * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the * * "Software"), to deal in the Software without restriction, including * * without limitation the rights to use, copy, modify, merge, publish, * * distribute, distribute with modifications, sublicense, and/or sell * * copies of the Software, and to permit persons to whom the Software is * * furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included * * in all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * * * Except as contained in this notice, the name(s) of the above copyright * * holders shall not be used in advertising or otherwise to promote the * * sale, use or other dealings in this Software without prior written * * authorization. * ****************************************************************************//****************************************************************************NAME ncurses.c --- ncurses library exerciserSYNOPSIS ncursesDESCRIPTION An interactive test module for the ncurses library.AUTHOR Author: Eric S. Raymond <esr@snark.thyrsus.com> 1993 Thomas E. Dickey (beginning revision 1.27 in 1996).$Id: ncurses.c,v 1.202 2004/02/07 20:24:08 tom Exp $***************************************************************************/#include <test.priv.h>#if HAVE_GETTIMEOFDAY#if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT#include <sys/time.h>#endif#if HAVE_SYS_SELECT_H#include <sys/select.h>#endif#endif#if USE_LIBPANEL#include <panel.h>#endif#if USE_LIBMENU#include <menu.h>#endif#if USE_LIBFORM#include <form.h>#endif#ifdef NCURSES_VERSION#ifdef TRACEstatic int save_trace = TRACE_ORDINARY | TRACE_CALLS;extern int _nc_tracing;#endif#else#define mmask_t chtype /* not specified in XSI */#ifdef CURSES_ACS_ARRAY#define ACS_S3 (CURSES_ACS_ARRAY['p']) /* scan line 3 */#define ACS_S7 (CURSES_ACS_ARRAY['r']) /* scan line 7 */#define ACS_LEQUAL (CURSES_ACS_ARRAY['y']) /* less/equal */#define ACS_GEQUAL (CURSES_ACS_ARRAY['z']) /* greater/equal */#define ACS_PI (CURSES_ACS_ARRAY['{']) /* Pi */#define ACS_NEQUAL (CURSES_ACS_ARRAY['|']) /* not equal */#define ACS_STERLING (CURSES_ACS_ARRAY['}']) /* UK pound sign */#else#define ACS_S3 (A_ALTCHARSET + 'p') /* scan line 3 */#define ACS_S7 (A_ALTCHARSET + 'r') /* scan line 7 */#define ACS_LEQUAL (A_ALTCHARSET + 'y') /* less/equal */#define ACS_GEQUAL (A_ALTCHARSET + 'z') /* greater/equal */#define ACS_PI (A_ALTCHARSET + '{') /* Pi */#define ACS_NEQUAL (A_ALTCHARSET + '|') /* not equal */#define ACS_STERLING (A_ALTCHARSET + '}') /* UK pound sign */#endif#ifdef CURSES_WACS_ARRAY#define WACS_S3 (&(CURSES_WACS_ARRAY['p'])) /* scan line 3 */#define WACS_S7 (&(CURSES_WACS_ARRAY['r'])) /* scan line 7 */#define WACS_LEQUAL (&(CURSES_WACS_ARRAY['y'])) /* less/equal */#define WACS_GEQUAL (&(CURSES_WACS_ARRAY['z'])) /* greater/equal */#define WACS_PI (&(CURSES_WACS_ARRAY['{'])) /* Pi */#define WACS_NEQUAL (&(CURSES_WACS_ARRAY['|'])) /* not equal */#define WACS_STERLING (&(CURSES_WACS_ARRAY['}'])) /* UK pound sign */#endif#endif#define P(string) printw("%s\n", string)#define BLANK ' ' /* this is the background character */#undef max_colorsstatic int max_colors; /* the actual number of colors we'll use */#undef max_pairsstatic int max_pairs; /* ...and the number of color pairs *//* The behavior of mvhline, mvvline for negative/zero length is unspecified, * though we can rely on negative x/y values to stop the macro. */static voiddo_h_line(int y, int x, chtype c, int to){ if ((to) > (x)) mvhline(y, x, c, (to) - (x));}static voiddo_v_line(int y, int x, chtype c, int to){ if ((to) > (y)) mvvline(y, x, c, (to) - (y));}/* Common function to allow ^T to toggle trace-mode in the middle of a test * so that trace-files can be made smaller. */static intwGetchar(WINDOW *win){ int c;#ifdef TRACE while ((c = wgetch(win)) == CTRL('T')) { if (_nc_tracing) { save_trace = _nc_tracing; _tracef("TOGGLE-TRACING OFF"); _nc_tracing = 0; } else { _nc_tracing = save_trace; } trace(_nc_tracing); if (_nc_tracing) _tracef("TOGGLE-TRACING ON"); }#else c = wgetch(win);#endif return c;}#define Getchar() wGetchar(stdscr)/* replaces wgetnstr(), since we want to be able to edit values */static voidwGetstring(WINDOW *win, char *buffer, int limit){ int y0, x0, x, ch; bool done = FALSE; echo(); getyx(win, y0, x0); wattrset(win, A_REVERSE); x = strlen(buffer); while (!done) { if (x > (int) strlen(buffer)) x = (int) strlen(buffer); wmove(win, y0, x0); wprintw(win, "%-*s", limit, buffer); wmove(win, y0, x0 + x); switch (ch = wGetchar(win)) { case '\n': case KEY_ENTER: done = TRUE; break; case CTRL('U'): *buffer = '\0'; break; case '\b': case KEY_BACKSPACE: case KEY_DC: if (x > 0) { int j; for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) { ; } } else { beep(); } break; case KEY_LEFT: if (x > 0) { --x; } else { flash(); } break; case KEY_RIGHT: ++x; break; default: if (!isprint(ch) || ch >= KEY_MIN) { beep(); } else if ((int) strlen(buffer) < limit) { int j; for (j = strlen(buffer) + 1; j > x; --j) { buffer[j] = buffer[j - 1]; } buffer[x++] = ch; } else { flash(); } } } wattroff(win, A_REVERSE); wmove(win, y0, x0); noecho();}#if USE_WIDEC_SUPPORTstatic intwGet_wchar(WINDOW *win, wint_t * result){ int c;#ifdef TRACE while ((c = wget_wch(win, result)) == CTRL('T')) { if (_nc_tracing) { save_trace = _nc_tracing; _tracef("TOGGLE-TRACING OFF"); _nc_tracing = 0; } else { _nc_tracing = save_trace; } trace(_nc_tracing); if (_nc_tracing) _tracef("TOGGLE-TRACING ON"); }#else c = wget_wch(win, result);#endif return c;}#define Get_wchar(result) wGet_wchar(stdscr, result)/* replaces wgetn_wstr(), since we want to be able to edit values */static voidwGet_wstring(WINDOW *win, wchar_t * buffer, int limit){ int y0, x0, x; wint_t ch; bool done = FALSE; echo(); getyx(win, y0, x0); wattrset(win, A_REVERSE); x = wcslen(buffer); while (!done) { if (x > (int) wcslen(buffer)) x = (int) wcslen(buffer); wmove(win, y0, x0); waddnwstr(win, buffer, limit); if (x < limit) wprintw(win, "%*s", limit - x, " "); wmove(win, y0, x0 + x); switch (wGet_wchar(win, &ch)) { case KEY_CODE_YES: switch (ch) { case KEY_ENTER: ch = '\n'; break; case KEY_BACKSPACE: case KEY_DC: ch = '\b'; break; case KEY_LEFT: case KEY_RIGHT: break; default: ch = (wint_t) - 1; break; } case OK: break; default: ch = (wint_t) - 1; break; } switch (ch) { case '\n': done = TRUE; break; case CTRL('U'): *buffer = '\0'; break; case '\b': if (x > 0) { int j; for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) { ; } } else { beep(); } break; case KEY_LEFT: if (x > 0) { --x; } else { flash(); } break; case KEY_RIGHT: ++x; break; default: if (!isprint(ch) || ch >= KEY_MIN) { beep(); } else if ((int) wcslen(buffer) < limit) { int j; for (j = wcslen(buffer) + 1; j > x; --j) { buffer[j] = buffer[j - 1]; } buffer[x++] = ch; } else { flash(); } } } wattroff(win, A_REVERSE); wmove(win, y0, x0); noecho();}#endifstatic voidPause(void){ move(LINES - 1, 0); addstr("Press any key to continue... "); (void) Getchar();}static voidCannot(const char *what){ printw("\nThis %s terminal %s\n\n", getenv("TERM"), what); Pause();}static voidShellOut(bool message){ if (message) addstr("Shelling out..."); def_prog_mode(); endwin(); system("sh"); if (message) addstr("returned from shellout.\n"); refresh();}#ifdef NCURSES_MOUSE_VERSIONstatic const char *mouse_decode(MEVENT const *ep){ static char buf[80]; (void) sprintf(buf, "id %2d at (%2d, %2d, %2d) state %4lx = {", ep->id, ep->x, ep->y, ep->z, ep->bstate);#define SHOW(m, s) if ((ep->bstate & m)==m) {strcat(buf,s); strcat(buf, ", ");} SHOW(BUTTON1_RELEASED, "release-1"); SHOW(BUTTON1_PRESSED, "press-1"); SHOW(BUTTON1_CLICKED, "click-1"); SHOW(BUTTON1_DOUBLE_CLICKED, "doubleclick-1"); SHOW(BUTTON1_TRIPLE_CLICKED, "tripleclick-1"); SHOW(BUTTON1_RESERVED_EVENT, "reserved-1"); SHOW(BUTTON2_RELEASED, "release-2"); SHOW(BUTTON2_PRESSED, "press-2"); SHOW(BUTTON2_CLICKED, "click-2"); SHOW(BUTTON2_DOUBLE_CLICKED, "doubleclick-2"); SHOW(BUTTON2_TRIPLE_CLICKED, "tripleclick-2"); SHOW(BUTTON2_RESERVED_EVENT, "reserved-2"); SHOW(BUTTON3_RELEASED, "release-3"); SHOW(BUTTON3_PRESSED, "press-3"); SHOW(BUTTON3_CLICKED, "click-3"); SHOW(BUTTON3_DOUBLE_CLICKED, "doubleclick-3"); SHOW(BUTTON3_TRIPLE_CLICKED, "tripleclick-3"); SHOW(BUTTON3_RESERVED_EVENT, "reserved-3"); SHOW(BUTTON4_RELEASED, "release-4"); SHOW(BUTTON4_PRESSED, "press-4"); SHOW(BUTTON4_CLICKED, "click-4"); SHOW(BUTTON4_DOUBLE_CLICKED, "doubleclick-4"); SHOW(BUTTON4_TRIPLE_CLICKED, "tripleclick-4"); SHOW(BUTTON4_RESERVED_EVENT, "reserved-4"); SHOW(BUTTON_CTRL, "ctrl"); SHOW(BUTTON_SHIFT, "shift"); SHOW(BUTTON_ALT, "alt"); SHOW(ALL_MOUSE_EVENTS, "all-events"); SHOW(REPORT_MOUSE_POSITION, "position");#undef SHOW if (buf[strlen(buf) - 1] == ' ') buf[strlen(buf) - 2] = '\0'; (void) strcat(buf, "}"); return (buf);}#endif /* NCURSES_MOUSE_VERSION *//**************************************************************************** * * Character input test * ****************************************************************************/static voidsetup_getch(WINDOW *win, bool flags[]){ keypad(win, flags['k']); /* should be redundant, but for testing */ meta(win, flags['m']); /* force this to a known state */ if (flags['e']) echo(); else noecho();}static voidwgetch_help(WINDOW *win, bool flags[]){ static const char *help[] = { "e -- toggle echo mode" ,"g -- triggers a getstr test" ,"k -- toggle keypad/literal mode" ,"m -- toggle meta (7-bit/8-bit) mode" ,"q -- quit (x also exits)" ,"s -- shell out\n" ,"w -- create a new window"#ifdef SIGTSTP ,"z -- suspend this process"#endif }; int y, x; unsigned chk = ((SIZEOF(help) + 1) / 2); unsigned n; getyx(win, y, x); move(0, 0); printw("Type any key to see its %s value. Also:\n", flags['k'] ? "keypad" : "literal"); for (n = 0; n < SIZEOF(help); ++n) { int row = 1 + (n % chk); int col = (n >= chk) ? COLS / 2 : 0; int flg = ((strstr(help[n], "toggle") != 0) && (flags[UChar(*help[n])] != FALSE)); if (flg) standout(); mvprintw(row, col, "%s", help[n]); if (col == 0) clrtoeol(); if (flg) standend(); } wrefresh(stdscr); wmove(win, y, x);}static voidwgetch_wrap(WINDOW *win, int first_y){ int last_y = getmaxy(win) - 1; int y = getcury(win) + 1; if (y >= last_y) y = first_y; wmove(win, y, 0); wclrtoeol(win);}#if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZEtypedef struct { WINDOW *text; WINDOW *frame;} WINSTACK;static WINSTACK *winstack = 0;static unsigned len_winstack = 0;static voidremember_boxes(unsigned level, WINDOW *txt_win, WINDOW *box_win){ unsigned need = (level + 1) * 2; if (winstack == 0) { len_winstack = 20; winstack = (WINSTACK *) malloc(len_winstack * sizeof(WINSTACK)); } else if (need >= len_winstack) { len_winstack = need; winstack = (WINSTACK *) realloc(winstack, len_winstack * sizeof(WINSTACK)); } winstack[level].text = txt_win; winstack[level].frame = box_win;}/* * For wgetch_test(), we create pairs of windows - one for a box, one for text. * Resize both and paint the box in the parent. */static voidresize_boxes(int level, WINDOW *win){ unsigned n; int base = 5; int high = LINES - base; int wide = COLS; touchwin(stdscr); wnoutrefresh(stdscr); /* FIXME: this chunk should be done in resizeterm() */ slk_touch(); slk_clear(); slk_noutrefresh(); for (n = 0; (int) n < level; ++n) { wresize(winstack[n].frame, high, wide); wresize(winstack[n].text, high - 2, wide - 2); high -= 2; wide -= 2; werase(winstack[n].text); box(winstack[n].frame, 0, 0); wnoutrefresh(winstack[n].frame); wprintw(winstack[n].text, "size %dx%d\n", getmaxy(winstack[n].text), getmaxx(winstack[n].text)); wnoutrefresh(winstack[n].text); if (winstack[n].text == win) break; } doupdate();}#else#define remember_boxes(level,text,frame) /* nothing */#endifstatic void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -