底层终端控制

 控制终端
POSIX.1定义了一个查询和操纵终端的标准接口termios,他是一个数据结构和一系列操作这些数据结构的函数,
    #include <termios.h>
    struct termios
    {
        tcflag_t c_iflag;       /* input mode flags */
        tcflag_t c_oflag;       /* output mode flags */
        tcflag_t c_cflag;       /* control mode flags */
        tcflag_t c_lflag;       /* local mode flags */
        cc_t c_line;            /* line discipline */
        cc_t c_cc[NCCS];        /* control characters */
        speed_t c_ispeed;       /* input speed */
        speed_t c_ospeed;       /* output speed */
    }
    c_iflag用来控制输入处理选项的,他将影响到终端驱动程序把输入发送给程序之前是否对其进行处理,以及处理的方式,同样,c_oflag用来控制输出的处理。c_cflag决定终端的硬件特性的控制标志。c_lflag用来决定本地终端的特性,例如输入时是否回显等,c_cc包含了特殊字符序列的值,以及他们所代表的操作。c_line表示控制协议。
   
    c_iflag flag constants:
        IGNBRK 忽略输入中的BREAK条件
        BRKINT 如果设置了IGNBRK,将在BREAK时产生SIGINT
        IGNPAR Ignore framing errors and parity errors.
        PARMRK If  IGNPAR is not set, prefix a character with a parity error or
                   framing error with \377 \0.  If neither  IGNPAR  nor  PARMRK  is
                   set,  read  a  character with a parity error or framing error as
                   \0.
        INPCK  Enable input parity checking.
        ISTRIP Strip off eighth bit.
        INLCR  将输入的CR转化成NL
        IGNCR  忽略输入中的CR
        ICRNL  Translate carriage return to newline on input (unless  IGNCR  is
                  set).
        IUCLC  (not in POSIX) Map uppercase characters to lowercase on input.
        IXON   Enable XON/XOFF flow control on output.
        IXANY  (XSI)  Typing  any  character will restart stopped output.  (The
                  default is to allow just the START character to restart output.)
        IXOFF  Enable XON/XOFF flow control on input.
        IMAXBEL
                  (not  in  POSIX) Ring bell when input queue is full.  Linux does
                  not implement this bit, and acts as if it is always set.

    c_oflag flag constants defined in POSIX.1:
        OLCUC  (not  in POSIX) Map lowercase characters to uppercase on output.
        ONLCR  将输出中的NL,转化成CR—NL
        OCRNL  将输出中的CR转换成NL
        ONOCR  Don’t output CR at column 0.
        ONLRET 不输出CR
        OFILL  Send fill characters for a delay,  rather  than  using  a  timed
            delay.
        OFDEL  (not  in  POSIX)  Fill character is ASCII DEL (0177).  If unset,
            fill character is ASCII NUL (’\0’).  (Not implemented on Linux.)
        NLDLY  Newline   delay  mask.   Values  are  NL0  and  NL1.   [requires
            _BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
        CRDLY  Carriage return delay mask.  Values are CR0, CR1, CR2,  or  CR3.
            requires _BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
        TABDLY Horizontal  tab  delay  mask.  Values are TAB0, TAB1, TAB2, TAB3
            (or XTABS).  A value of TAB3, that is, XTABS,  expands  tabs  to
            spaces   (with   tab  stops  every  eight  columns).   [requires
            _BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]
        BSDLY  Backspace delay mask.  Values are BS0 or BS1.  (Has  never  been
            implemented.)    [requires   _BSD_SOURCE   or   _SVID_SOURCE  or
            _XOPEN_SOURCE]
        VTDLY  Vertical tab delay mask.  Values are VT0 or VT1.
        FFDLY  Form feed  delay  mask.   Values  are  FF0  or  FF1.   [requires
            _BSD_SOURCE or _SVID_SOURCE or _XOPEN_SOURCE]

    c_cflag flag constants:
        CBAUD  (not   in   POSIX)   Baud  speed  mask  (4+1  bits).   [requires
            _BSD_SOURCE or _SVID_SOURCE]
        CBAUDEX (not in POSIX) Extra baud speed mask (1 bit), included in CBAUD.
            [requires _BSD_SOURCE or _SVID_SOURCE]
            (POSIX  says that the baud speed is stored in the termios struc-
            ture  without   specifying   where   precisely,   and   provides
            cfgetispeed()  and cfsetispeed() for getting at it. Some systems
            use bits selected by CBAUD in c_cflag, other systems  use  sepa-
            rate fields, e.g.  sg_ispeed and sg_ospeed.)
        CSIZE  Character size mask.  Values are CS5, CS6, CS7, or CS8.
        CSTOPB Set two stop bits, rather than one.
        CREAD  Enable receiver.
        PARENB Enable  parity  generation  on  output  and  parity checking for
            input.
        PARODD Parity for input and output is odd.
        HUPCL  在最后处理结束时,关闭设备并关闭连接
        CLOCAL 忽略调制解调器控制线
        LOBLK  (not  in POSIX) Block output from a noncurrent shell layer.  For
            use by shl (shell layers).  (Not implemented on Linux.)
        CIBAUD (not in POSIX) Mask for input speeds. The values for the  CIBAUD
            bits are the same as the values for the CBAUD bits, shifted left
            IBSHIFT  bits.   [requires  _BSD_SOURCE  or  _SVID_SOURCE]  (Not
            implemented on Linux.)
        CRTSCTS (not   in   POSIX)   Enable  RTS/CTS  (hardware)  flow  control.
            [requires _BSD_SOURCE or _SVID_SOURCE]
           
    c_lflag flag constants:
        ISIG   When any of the  characters  INTR,  QUIT,  SUSP,  or  DSUSP  are
            received, generate the corresponding signal.
        ICANON 启用规范模式
        XCASE  (not in POSIX; not supported under Linux) If ICANON is also set,
            terminal is uppercase only.  Input is  converted  to  lowercase,
            except for characters preceded by \.  On output, uppercase char-
            acters are preceded by \ and lowercase characters are  converted
            to uppercase.
        ECHO   输入回显
        ECHOE  If  ICANON is also set, the ERASE character erases the preceding
            input character, and WERASE erases the preceding word.
        ECHOK  If ICANON is also set, the KILL  character  erases  the  current
            line.
        ECHONL 在规范模式中,即使没有设置ECHO也回显NL
        ECHOCTL
            (not in POSIX) If ECHO is also set, ASCII control signals  other
            than  TAB,  NL, START, and STOP are echoed as ^X, where X is the
            character with ASCII code 0x40 greater than the control  signal.
            For  example,  character  0x08  (BS) is echoed as ^H.  [requires
            _BSD_SOURCE or _SVID_SOURCE]
        ECHOPRT
            (not in POSIX) If ICANON and IECHO are also set, characters  are
            printed  as  they  are  being  erased.  [requires _BSD_SOURCE or
            _SVID_SOURCE]
        ECHOKE (not in POSIX) If ICANON is also set, KILL is echoed by  erasing
            each  character  on the line, as specified by ECHOE and ECHOPRT.
            [requires _BSD_SOURCE or _SVID_SOURCE]
        DEFECHO (not in POSIX) Echo only when a process is reading.  (Not imple-
            mented on Linux.)
        FLUSHO (not  in  POSIX;  not  supported  under  Linux)  Output is being
            flushed.  This flag is toggled by typing the DISCARD  character.
            [requires _BSD_SOURCE or _SVID_SOURCE]
        NOFLSH Disable flushing the input and output queues when generating the
            SIGINT, SIGQUIT and SIGSUSP signals.
        TOSTOP Send the SIGTTOU signal to the process  group  of  a  background
            process which tries to write to its controlling terminal.
        PENDIN (not  in POSIX; not supported under Linux) All characters in the
            input queue are reprinted  when  the  next  character  is  read.
            (bash  handles  typeahead  this  way.)  [requires _BSD_SOURCE or
            _SVID_SOURCE]
        IEXTEN Enable implementation-defined input processing.  This  flag,  as
            well as ICANON must be enabled for  the special characters EOL2,
            LNEXT, REPRINT, WERASE to be interpreted, and for the IUCLC flag
            to be effective.
    The  c_cc  array  defines the special control characters.
        VINTR  (003, ETX, Ctrl-C, or also 0177, DEL, rubout) Interrupt  charac-
            ter.  Send  a  SIGINT  signal.  Recognized when ISIG is set, and
            then not passed as input.
        VQUIT  (034, FS, Ctrl-\) Quit character. Send SIGQUIT  signal.   Recog-
            nized when ISIG is set, and then not passed as input.
        VERASE (0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) Erase charac-
            ter. This erases the previous not-yet-erased character, but does
            not erase past EOF or beginning-of-line.  Recognized when ICANON
            is set, and then not passed as input.
        VKILL  (025, NAK, Ctrl-U, or Ctrl-X, or also @)  Kill  character.  This
            erases  the input since the last EOF or beginning-of-line.  Rec-
            ognized when ICANON is set, and then not passed as input.
        VEOF   (004, EOT, Ctrl-D) End-of-file character.  More precisely:  this
            character  causes the pending tty buffer to be sent to the wait-
            ing user program without waiting for end-of-line.  If it is  the
            first  character  of  the  line,  the read() in the user program
            returns 0, which signifies end-of-file.  Recognized when  ICANON
            is set, and then not passed as input.
        VMIN   Minimum number of characters for non-canonical read.
        VEOL   (0,  NUL)  Additional  end-of-line  character.   Recognized when
            ICANON is set.
        VTIME  Timeout in deciseconds for non-canonical read.
        VEOL2  (not in POSIX; 0, NUL) Yet another end-of-line character.   Rec-
            gnized when ICANON is set.
        VSWTCH (not in POSIX; not supported under Linux; 0, NUL) Switch charac-
            ter. (Used by shl only.)
        VSTART (021, DC1, Ctrl-Q) Start character. Restarts output  stopped  by
            the  Stop  character.  Recognized when IXON is set, and then not
            passed as input.
        VSTOP  (023, DC3, Ctrl-S) Stop character. Stop output until Start char-
            acter  typed.   Recognized when IXON is set, and then not passed
            as input.
        VSUSP  (032, SUB, Ctrl-Z) Suspend character. Send SIGTSTP signal.  Rec-
            ognized when ISIG is set, and then not passed as input.
        VDSUSP (not  in  POSIX;  not  supported  under  Linux; 031, EM, Ctrl-Y)
            Delayed suspend character: send SIGTSTP signal when the  charac-
            ter  is  read  by  the user program.  Recognized when IEXTEN and
            ISIG are set, and the system supports job control, and then  not
            passed as input.
        VLNEXT (not  in  POSIX; 026, SYN, Ctrl-V) Literal next. Quotes the next
            input character, depriving it of  a  possible  special  meaning.
            Recognized when IEXTEN is set, and then not passed as input.
        VWERASE
            (not  in  POSIX;  027, ETB, Ctrl-W) Word erase.  Recognized when
            ICANON and IEXTEN are set, and then not passed as input.
        VREPRINT
            (not in POSIX; 022,  DC2,  Ctrl-R)  Reprint  unread  characters.
            Recognized  when  ICANON and IEXTEN are set, and then not passed
            as input.
        VDISCARD
            (not in POSIX; not supported under Linux; 017, SI, Ctrl-O)  Tog-
            gle: start/stop discarding pending output.  Recognized when IEX-
            TEN is set, and then not passed as input.
        VSTATUS
            (not in POSIX; not supported under Linux; status  request:  024,
            DC4, Ctrl-T).

        #include <termios.h>
        #include <unistd.h>
        int     tcgetattr   (int fd, struct termios *termios_p);
        int     tcsetattr   (int fd, int optional_actions, const struct termios *termios_p);

        int     tcsendbreak (int fd, int duration);
        int     tcdrain     (int fd);
        int     tcflush     (int fd, int queue_selector);
        int     tcflow      (int fd, int action);
        void    cfmakeraw   (struct termios *termios_p);

        speed_t cfgetispeed (const struct termios *termios_p);
        speed_t cfgetospeed (const struct termios *termios_p);
        int     cfsetispeed (struct termios *termios_p, speed_t speed);
        int     cfsetospeed (struct termios *termios_p, speed_t speed);
属性控制
    tcgetattr用来查询和fd相关联的终端的参数,并将他们存储到termios_p中,成功返回0,失败返回-1。
    tcsetattr用来设置终端的属性,其中optional_actions决定了改变什么时候生效,他的值可以为:
        TCSANOW     立即改变这些属性值
        TCSADRAIN   改变发生在当所有fd上的输出都已经被发送到终端以后,当要改变输出设置时
                使用此函数
        TCSAFLUSH   改变发生在当所有fd上的输出都已经被发送到终端以后,但任何挂起的输入
                将会被丢弃。
速度控制
    上面列出的速度控制函数都是成对出现,用来获取和设置相应的动作,其中要说明的是cfsetospeed的speed参数必须是下面列出的常数中的一个:
        B0(关闭连接)  B50
        B75     B110
        B134        B150
        B200        B300
        B600        B1200
        B1800       B2400
        B4800       B9600
        B19200      B38400
        B57600      B115200
        B230400
行控制
    tcdrain函数将一直保持等待,直到所有的输出都已经写入到文件描述符fd指向的文件为止。
    为了强迫输入,输出或者两者同时刷新,便可以使用tcflush函数,queue_selector用来指定要刷新的数据,他的取值如下:
        TCIFLUSH  flushes data received but not read.
        TCOFLUSH  flushes data written but not transmitted.
        TCIOFLUSH flushes  both data received but not read, and data written but
               not transmitted.
    实际的流量控制,不管是处于开状态还是关状态,都由tcflow来控制,参数action用来控制函数的动作,他的取值如下:
        TCOOFF suspends output.
        TCOON  restarts suspended output.
        TCIOFF transmits a STOP character, which stops the terminal device from
            transmitting data to the system.
        TCION  transmits a START character, which starts the terminal  device
            transmitting data to the system.

进程控制
        #include <unistd.h>
        pid_t tcgetpgrp(int fd);
        int   tcsetpgrp(int fd, pid_t pgrp);
    函数tcgetpgrp返回fd终端上前台运行的进程组pgrp_id的进程组标识号
    如果有足够的权限,使用tcsetpgrp可以改变进程组的标识号


使用terminfo
    对于每种可能的终端类型,terminfo维护了其终端能力和特性的一个列表,被称为capname,capname可以分为:布尔型,数值型,字符串型。其中,布尔型只能表示是否支持某一特定属性,数值型用来定义和大小有关的能力,字符串型定义访问某种特性的转义序列或者定义当用户按下任意键的动作。
        常用的终端能力(详细的可查询terminfo(5))
    capname     type        描述
    am      b (bool)    具有自动页边空白
    bce     b       使用背景色清除
    km      b       有META键
    ul      b       下划线字符加粗
    cols        i (int)     当前终端列数
    lines       i       当前终端行数
    colors      i       支持的颜色数
    clear       s (strring) 清屏并将光标移动到初始位置
    cl      s       清除行内容
    ed      s       清除到屏尾的内容
    smcup       s       进入光标寻址模式
    cup     s       移动光标
    rmcup       s       退出光标寻址模式
    bel     s       蜂鸣
    flash       s       闪屏
    kf[0-63]    s       功能键F[0-63]
   
    为了使用terminfo必须包含curses.h和term.h

使用步骤:
    1,初始化terminfo数据结构
    2,检索capname 
    3,修改capname
    4,将修改后的capname输出到终端
    5,其他
    6,重复2-5

1,初始化
    #include <curses.h>
    #include <term.h>
    int setupterm(char *term, int fildes, int *errret);
    term用来指定终端类型,如果为NULL,则会读取环境变量TERM的值,否则,就会使用term所指定的终端类型。所有的输出都将会发送到由fildes指示的文件或设备中,如果errret不是NULL,1表示成功,0表示在terminfo没有找到term所指示的终端,-1表示terminfo数据库没有找到。返回OK表示调用成功,ERR表示失败。

2,检索
    int tigetflag(char *capname);
    int tigetnum(char *capname);
    char *tigetstr(char *capname);
    他们分别用来检索布尔型,数值型,字符串型
    tigetflag支持返回TRUE,不支持返回FALSE,如果检索的不是布尔型,就返回-1;
    tigetnum不支持capname返回-1,如果不是数值型,返回-2。
    tigetstr返回包含capname的转义序列,如果不支持capname返回(char *)NULL, 如果不是字符串型返回(char *)-1;

3,修改
    在发送控制字符串之前,你必须线构造他,这就是tparm的工作。
    char *tparm(char *str, ...);
    成功时返回一个被恰当格式化过的字符串,失败则返回NULL。
4,输出到终端
    int tputs(const char *str, int affcnt, int (*putc)(int));
    int putp(const char *str);
    putp是将str输出到标准输出上,他等价与tputs(str,1,putchar)
    tputs将str输出到setupterm中指定的term和fildes,str必须是一个terminfo字符串变量或者调用taprm或tigetstr的返回值,如果str是与行相关的能力,则affcnt便是将会影响的行数,putc是一个指向putchar风格(一次输出一个字符)的指针。

#include <stdlib.h>
#include <stdio.h>
#include <term.h>
#include <curses.h>

int main(void)
{
 int i;
 char *buf;

 if (ERR == setupterm(NULL, fileno(stdin), NULL))
 {
  perror("failed on setupterm\n");
  exit(EXIT_FAILURE);
 }
 i = tigetflag("km");
 printf("km = %d\n", i);
 i = tigetnum("lines");
 printf("lines = %d\n", i);
 buf = tigetstr("flash");
 printf("bel = \\E%s\n", &buf[1]);
 
 return 0;
}

#include <stdio.h>
#include <stdlib.h>
#include <termios.h>

int main(void)
{
 struct termios old, new;
 char passwd[32] = {0};
 
 if (-1 == tcgetattr(fileno(stdin), &old)) /*get ols attr.*/
 {
  perror("failed on tcgetattr\n");
  exit(EXIT_FAILURE);
 }
 
 new = old;
 new.c_lflag &= ~ECHO;  /*NO ECHO*/
 new.c_lflag |= ECHONL; /*echo nl*/
 
 if (-1 == tcsetattr(fileno(stdin), TCSANOW, &new)) /*set new attr*/
 {
  perror("failed on tcsetattr\n");
  exit(EXIT_FAILURE);
 }
 
 if ((-1 == tcgetattr(fileno(stdin), &new))) /*check set*/
 {
  perror("failure set\n");
  exit(EXIT_FAILURE);
 }
 if (new.c_lflag & ECHO)
 {
  puts("error on ECHO");
  exit(EXIT_FAILURE);
 }
 if (!new.c_lflag & ECHONL)
 {
  puts("error on ECHONL");
  exit(EXIT_FAILURE); 
 }
 
 puts("Input passwd:");
 fgets(passwd, 31, stdin);
 puts(passwd);
 
 tcsetattr(fileno(stdin), TCSANOW, &old); /*reset to old*/
 
 return 0;
}

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <termios.h>

void err(const char * str);
static void sig_catch(int sig);
int main(void)
{
 int fd = fileno(stdin);
 char c;
 struct termios old, new;
 
 if (signal(SIGINT, sig_catch) == SIG_ERR
  || signal(SIGQUIT, sig_catch) == SIG_ERR
  || signal(SIGTERM, sig_catch) == SIG_ERR)
  err("faile on signal\n");
 
 if (-1 == tcgetattr(fd, &old))
  err("failed on tcgetattr\n");
 new = old;
 new.c_lflag &= ~(ECHO | ICANON | ISIG);
 new.c_iflag &= ~(BRKINT | ICRNL);
 new.c_oflag &= ~OPOST;
 new.c_cc[VTIME] = 0;
 new.c_cc[VMIN]  = 1;
 if (-1 == tcsetattr(fd, TCSAFLUSH, &new))
  err("failed on tcsetattr");
 
 puts("Input keys:");
 while (1)
 {
  if (1 != read(fd, &c, 1))
   break;
  if (0161 == c)
   break;
  printf("%o\n",c);
 }
 
 tcsetattr(fd, TCSANOW, &old);
 return 0;
}

static void sig_catch(int sig)
{
 printf("Catch : %d\n",sig);
}

void err(const char * str)
{
 perror(str);
 exit(EXIT_FAILURE);
}

#include <stdio.h>
#include <stdlib.h>
#include <term.h>
#include <curses.h>

void moveto(int y, int x);
void clrscr(void);
void err(const char * str);
int main(void)
{
 int i;
 
 if (-1 == setupterm(NULL, fileno(stdout), NULL))
  err("setupinfo");
 printf("test...\n");
 getchar();
 clrscr();
 moveto(3, 3);
 i = tigetflag("km");
 printf("km = %d\n", i);
 printf("lines : %d cols : %d\n",
  tigetnum("lines"), tigetnum("cols"));
 moveto(10, 10);
 printf("X");
 moveto(1, 1);
 printf("x");

 return 0;
}

void moveto(int y, int x)
{
 char * buf = tigetstr("cup");
 putp(tparm(buf, y, x));
}

void clrscr(void)
{
 char *buf = tigetstr("clear");
 putp(buf);
}

void err(const char *str)
{
 printf("Error on %s\n", str);
 exit(EXIT_FAILURE);
}


 

你可能感兴趣的:(input,character,终端,Signal,output,Constants)