#include "term.h" #include "debug.h" enum KEY_ACTION{ KEY_NULL = 0, /* NULL */ CTRL_A = 1, /* Ctrl+a */ CTRL_B = 2, /* Ctrl-b */ CTRL_C = 3, /* Ctrl-c */ CTRL_D = 4, /* Ctrl-d */ CTRL_E = 5, /* Ctrl-e */ CTRL_F = 6, /* Ctrl-f */ CTRL_H = 8, /* Ctrl-h */ TAB = 9, /* Tab */ CTRL_K = 11, /* Ctrl+k */ CTRL_L = 12, /* Ctrl+l */ ENTER = 13, /* Enter */ CTRL_N = 14, /* Ctrl-n */ CTRL_P = 16, /* Ctrl-p */ CTRL_T = 20, /* Ctrl-t */ CTRL_U = 21, /* Ctrl+u */ CTRL_W = 23, /* Ctrl+w */ ESC = 27, /* Escape */ BACKSPACE = 127 /* Backspace */ }; #define T_ESC "\x1b" //setup initial terminal stuff //this coulc act differently, becouse allways there is //different terminal setting that should be default int term_init( term_screen *term ) { int ret=0; memset( term, 0, sizeof( term_screen )); if ( !isatty(STDIN_FILENO) ) { ERROR("isatty failed\n") goto exit_error; } //!!!!!! //register atexit term->ifd = STDIN_FILENO; term->ofd = STDOUT_FILENO; //if you whant raw mode then you should set it man if ( tcgetattr( term->ifd, &term->orig_i ) == -1 ) goto exit_error; term->raw_i = term->orig_i; term->mode = SCREEN_MODE_80x25; return ret; exit_error: errno = ENOTTY; return -1; } //get maximal number of columns setting up cursor to 999 column //and getting on with place terminal have placed cursor and getting //column on with terminal putted cursor int term_get_maxcol( term_screen *ts ) { int ret=-1; int orig_c; int cur_c; /* get initial cursor position */ if ( (orig_c = term_cur_pos_c( ts )) == -1 ) goto exit_error; /* go to right marging and get position */ if ( write( ts->ofd, T_ESC "[999C", 6 ) != 6 ) goto exit_error; if ( (cur_c = term_cur_pos_c( ts )) == -1 ) goto exit_error; ret = cur_c; /* restore position */ { char buf[32]; snprintf( buf, 32, T_ESC "[" "%d" "D", cur_c-orig_c); write( ts->ofd, buf, strlen(buf) ); } return ret; exit_error: return -1; } //try to setup far away line after that read position where //terminal have putted cursor and read line of that postion int term_get_maxrow( term_screen *ts ) { int ret=-1; int orig_r; int cur_r; /* get initial cursor position */ if ( (orig_r = term_cur_pos_r( ts )) == -1 ) goto exit_error; /* go to right marging and get position */ if ( write( ts->ofd, T_ESC "[999B", 6 ) != 6 ) goto exit_error; if ( (cur_r = term_cur_pos_r( ts )) == -1 ) goto exit_error; ret = cur_r; /* restore position */ { char buf[32]; snprintf( buf, 32, T_ESC "[" "%d" "A", cur_r-orig_r); write( ts->ofd, buf, strlen(buf) ); } return ret; exit_error: return -1; } int term_cur_pos( term_screen *ts ) { int ret=-1; return ret; } int term_cur_pos_c( term_screen *ts ) { unsigned int i; int row, col; char buf[32]; if ( write( ts->ofd, "\x1b[6n", 4 ) != 4 ) goto exit_error; i = 0; while (i < sizeof(buf)-1) { if ( read( ts->ifd, buf+i,1 ) != 1 ) break; if (buf[i] == 'R') break; i++; } buf[i] = '\0'; /* Parse terminal response */ if ( buf[0] != '\x1b' || buf[1] != '[' ) goto exit_error; if ( sscanf( buf+2, "%d;%d", &row, &col) != 2 ) goto exit_error; return col; exit_error: return -1; } int term_cur_pos_r( term_screen *ts ) { unsigned int i; int row, col; char buf[32]; if ( write( ts->ofd, "\x1b[6n", 4 ) != 4 ) goto exit_error; i = 0; while (i < sizeof(buf)-1) { if ( read( ts->ifd, buf+i,1 ) != 1 ) break; if (buf[i] == 'R') break; i++; } buf[i] = '\0'; /* Parse terminal response */ if ( buf[0] != '\x1b' || buf[1] != '[' ) goto exit_error; if ( sscanf( buf+2, "%d;%d", &row, &col) != 2 ) goto exit_error; return row; exit_error: return -1; } //set cursor column position int term_cur_set_c( term_screen *ts, unsigned int pc ) { int ret = 0; int cur_r; /* go to right marging and get position */ if ( (cur_r = term_cur_pos_r( ts )) == -1 ) goto exit_error; /* set position */ { char buf[32]; int l; snprintf( buf, 32, T_ESC "[%d;%dH", cur_r, pc); l = strlen( buf ); if ( write( ts->ofd, buf, l ) != l) goto exit_error; } return ret; exit_error: return -1; } //set cursor row/line position int term_cur_set_r( term_screen *ts, unsigned int pr ) { int ret = 0; int cur_c; /* go to right marging and get position */ if ( (cur_c = term_cur_pos_c( ts )) == -1 ) goto exit_error; /* set position */ { char buf[32]; int l; snprintf( buf, 32, T_ESC "[%d;%dH", pr, cur_c); l = strlen( buf ); if ( write( ts->ofd, buf, l ) != l) goto exit_error; } return ret; exit_error: return -1; } int term_set_speed( term_screen *ts ) { int ret = -1; return ret; } //clean terminal with escape command int term_clr_scr( term_screen *ts ) { int ret = 0; if ( write( ts->ofd, T_ESC "[H" T_ESC "[2J", 7 ) <= 0 );; return ret; } //set terminal default input/output behavior int term_set_raw_mode( term_screen *ts ) { int ret = 0; if ( tcgetattr( ts->ifd, &ts->orig_i ) == -1 ) { ERROR("Cannot get input terminal attributes\n"); goto exit_error; } ts->raw_i = ts->orig_i; /* modify the original mode */ /* input modes: no break, no CR to NL, no parity check, no strip char, * no start/stop output control. */ ts->raw_i.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); /* output modes - disable post raw */ ts->raw_i.c_oflag &= ~(OPOST); /* control modes - set 8 bit chars */ ts->raw_i.c_cflag |= (CS8); /* local modes - choing off, canonical off, no extended functions, * no signal chars (^Z,^C) */ ts->raw_i.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); /* control chars - set return condition: min number of bytes and timer. * We want read to return every single byte, without timeout. */ ts->raw_i.c_cc[VMIN] = 1; ts->raw_i.c_cc[VTIME] = 0; /* 1 byte, no timer */ /* put terminal in raw mode after flushing */ if (tcsetattr( ts->ifd, TCSAFLUSH, &ts->raw_i) < 0) { ERROR("Cannot set new terminal input attribures\n"); goto exit_error; } return ret; exit_error: errno = ENOTTY; return -1; } //if there is no mode with some rows/columns , then just show that no mode setet // up and user should decide by his own what to do int term_mode_rows( term_screen *ts ) { int ret = -1; if ( ts == NULL) return -1; switch ( ts->mode ) { //--------------------- case SCREEN_MODE_80x25: ret = 25; break; //-------------------- case SCREEN_MODE_NONE: default: ret = -1; } return ret; } //if there is no mode with some rows/columns , then just show that no mode setet // up and user should decide by his own what to do int term_mode_columns( term_screen *ts ) { int ret = -1; if ( ts == NULL) return -1; switch ( ts->mode ) { //--------------------- case SCREEN_MODE_80x25: ret = 80; break; //-------------------- case SCREEN_MODE_NONE: default: ret = -1; } return ret; } void term_set_orig_mode( term_screen *ts ) { tcsetattr( ts->ifd, TCSAFLUSH, &ts->orig_i ); }