termios结构体详解

termios 结构是在POSIX规范中定义的标准接口,它类似于系统V中的termio接口,通过设置termios类型的数据结构中的值和使用一小组函数调用,你就可以对终端接口进行控制。

可以被调整来影响终端的值按照不同的模式被分为如下几组:

1.输入模式

2.输出模式

3.控制模式

4.本地模式

5.特殊控制模式

termios结构类型包括若干个标志集和一个控制字符的数组,所有的Unix版本包含以下结构体:

struct termios

{

       tcflag_tc_iflag;             //输入模式标志
      
tcflag_tc_oflag;            //输出模式标志
      
tcflag_tc_cflag;            //控制模式标志
      
tcflag_tc_lflag;            //本地模式标志
      
cc_t    c_cc[NCCS];     //控制字符

       speed_tc_isspeed;      //输入波特率

       speed_tc_ospedd;       //输出波特率

}

1c_iflag:输入模式标志,控制终端输入方式,具体参数如下所示。

 

    

    

IGNBRK

忽略BREAK键输入

BRKINT

如果设置了IGNBRKBREAK键的输入将被忽略,如果设置了BRKINT ,将产生SIGINT中断

IGNPAR

忽略奇偶校验错误

PARMRK

标识奇偶校验错误

INPCK

允许输入奇偶校验

ISTRIP

去除字符的第8个比特

INLCR

将输入的NL(换行)转换成CR(回车)

IGNCR

忽略输入的回车

ICRNL

将输入的回车转化成换行(如果IGNCR未设置的情况下)

IUCLC

将输入的大写字符转换成小写字符(非POSIX

IXON

允许输入时对XON/XOFF流进行控制

IXANY

输入任何字符将重启停止的输出

IXOFF

允许输入时对XON/XOFF流进行控制

IMAXBEL

当输入队列满的时候开始响铃,Linux在使用该参数而是认为该参数总是已经设置

2c_oflag:输出模式标志,控制终端输出方式,具体参数如下所示。

 

    

    

OPOST

处理后输出

OLCUC

将输入的小写字符转换成大写字符(非POSIX

ONLCR

将输入的NL(换行)转换成CR(回车)及NL(换行)

OCRNL

将输入的CR(回车)转换成NL(换行)

ONOCR

第一行不输出回车符

ONLRET

不输出回车符

OFILL

发送填充字符以延迟终端输出

OFDEL

ASCII码的DEL作为填充字符,如果未设置该参数,填充字符将是NUL‘\0’)(非POSIX

NLDLY

换行输出延时,可以取NL0(不延迟)或NL1(延迟0.1s

CRDLY

回车延迟,取值范围为:CR0CR1CR2 CR3

TABDLY

水平制表符输出延迟,取值范围为:TAB0TAB1TAB2TAB3

BSDLY

空格输出延迟,可以取BS0BS1

VTDLY

垂直制表符输出延迟,可以取VT0VT1

FFDLY

换页延迟,可以取FF0FF1

3c_lflag:本地模式标志,控制终端编辑功能,具体参数如下所示。

 

    

    

ISIG

当输入INTRQUITSUSPDSUSP时,产生相应的信号

ICANON

使用标准输入模式

XCASE

ICANONXCASE同时设置的情况下,终端只使用大写。如果只设置了XCASE,则输入字符将被转换为小写字符,除非字符使用了转义字符(非POSIX,且Linux不支持该参数)

ECHO

显示输入字符

ECHOE

如果ICANON同时设置,ERASE将删除输入的字符,WERASE将删除输入的单词

ECHOK

如果ICANON同时设置,KILL将删除当前行

ECHONL

如果ICANON同时设置,即使ECHO没有设置依然显示换行符

ECHOPRT

如果ECHOICANON同时设置,将删除打印出的字符(非POSIX

TOSTOP

向后台输出发送SIGTTOU信号

4c_cflag:控制模式标志,指定终端硬件控制信息,具体参数如下所示。

 

    

    

CBAUD

波特率(4+1位)(非POSIX

CBAUDEX

附加波特率(1位)(非POSIX

CSIZE

字符长度,取值范围为CS5CS6CS7CS8

CSTOPB

设置两个停止位

CREAD

使用接收器

PARENB

使用奇偶校验

PARODD

对输入使用奇偶校验,对输出使用偶校验

HUPCL

关闭设备时挂起

CLOCAL

忽略调制解调器线路状态

CRTSCTS

使用RTS/CTS流控制

5c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等。


只有在本地模式标志c_lflag中设置了IEXITEN时,POSIX没有定义的控制字符才能在Linux中使用。每个控制字符都对应一个按键组合(^C^H等),但VMINVTIME这两个控制字符除外,它们不对应控制符。这两个控制字符只在原始模式下才有效。

    

c_cc[VINTR]

默认对应的控制符是^C,作用是清空输入和输出队列的数据并且向tty设备的前台进程组中的每一个程序发送一个SIGINT信号,对SIGINT号没有定义处理程序的进程会马上退出。

c_cc[VQUIT]

默认对应的控制符是^/,作用是清空输入和输出队列的数据并向tty设备的前台进程组中的每一个程序发送一个SIGQUIT信号,对SIGQUIT 信号没有定义处理程序的进程会马上退出。

c_cc[verase]

默认对应的控制符是^H^?,作用是在标准模式下,删除本行前一个字符,该字符在原始模式下没有作用。

c_cc[VKILL]

默认对应的控制符是^U,在标准模式下,删除整行字符,该字符在原始模式下没有作用。

c_cc[VEOF]

默认对应的控制符是^D,在标准模式下,使用read()返回0,标志一个文件结束。

c_cc[VSTOP]

默认对应的控制字符是^S,作用是使用tty设备暂停输出直到接收到VSTART控制字符。或者,如果设备了IXANY,则等收到任何字符就开始输出。

c_cc[VSTART]

默认对应的控制字符是^Q,作用是重新开始被暂停的tty设备的输出。

c_cc[VSUSP]

默认对应的控制字符是^Z,使当前的前台进程接收到一个SIGTSTP信号。

c_cc[VEOL]c_cc[VEOL2]

在标准模式下,这两个下标在行的末尾加上一个换行符('/n'),标志一个行的结束,从而使用缓冲区中的数据被发送,并开始新的一行。POSIX没有定义VEOL2

c_cc[VREPRINT]

默认对应的控制符是^R,在标准模式下,如果设置了本地模式标志ECHO,使用VERPRINT对应的控制符和换行符在本地显示,并且重新打印当前缓冲区中的字符。POSIX中没有定义VERPRINT

c_cc[VWERASE]

默认对应的控制字符是^W,在标准模式下,删除缓冲区末端的所有空格符,然后删除与之相邻的非空格符,从而起到在一行中删除前一个单词的效果。 POSIX中没有定义VWERASE

c_cc[VLNEXT]

默认对应的控制符是^V,作用是让下一个字符原封不动地进入缓冲区。如果要让^V字符进入缓冲区,需要按两下^VPOSIX中没有定义 VLNEXT

 

与结构体相关的函数

(1)   tcgetattr()

原型:int tcgetattr(int fd,structtermois & termios_p);

功能:取得终端介质(fd)初始值,并把其值赋给temios_p;函数可以从后台进程中调用;但是,终端属性可能被后来的前台进程所改变。


2tcsetattr() 

原型:inttcsetattr(int fd,int actions,const struct    termios*termios_p);

功能:设置与终端相关的参数 (除非需要底层支持却无法满足),使用termios_p 引用的termios 结构。optional_actionstcsetattr函数的第二个参数)指定了什么时候改变会起作用: 
TCSANOW
:改变立即发生  
TCSADRAIN:改变在所有写入fd 的输出都被传输后生效。这个函数应当用于修改影响输出的参数时使用。(当前输出完成时将值改变)  
TCSAFLUSH :改变在所有写入fd 引用的对象的输出都被传输后生效,所有已接受但未读入的输入都在改变发生前丢弃(TCSADRAIN,但会舍弃当前所有值) 


3tcsendbreak()
 
传送连续的0 值比特流,持续一段时间,如果终端使用异步串行数据传输的话。如果duration 0,它至少传输 0.25 秒,不会超过 0.5 秒。如果 duration非零,它发送的时间长度由实现定义。 
如果终端并非使用异步串行数据传输,tcsendbreak()什么都不做。
4tcdrain() 
等待直到所有写入fd 引用的对象的输出都被传输。
5tcflush() 
丢弃要写入引用的对象,但是尚未传输的数据,或者收到但是尚未读取的数据,取决于queue_selector 的值:

TCIFLUSH:刷新收到的数据但是不读  
TCOFLUSH :刷新写入的数据但是不传送  
TCIOFLUSH :同时刷新收到的数据但是不读,并且刷新写入的数据但是不传送 

6tcflow() 
挂起 fd 引用的对象上的数据传输或接收,取决于action 的值:

TCOOFF:挂起输出  
TCOON :重新开始被挂起的输出  
TCIOFF :发送一个STOP 字符,停止终端设备向系统传送数据  
TCION :发送一个START 字符,使终端设备向系统传输数据  
打开一个终端设备时的默认设置是输入和输出都没有挂起。
(7)
波特率函数 
被用来获取和设置termios 结构中,输入和输出波特率的值。新值不会马上生效,直到成功调用了tcsetattr() 函数。
设置速度为 B0 使得 modem"挂机"。与 B38400 相应的实际比特率可以用setserial(8) 调整。 输入和输出波特率被保存于 termios 结构中。 
cfmakeraw
设置终端属性如下: 
           termios_p->c_iflag &=~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
           termios_p->c_oflag &= ~OPOST;
           termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
           termios_p->c_cflag &= ~(CSIZE|PARENB);
           termios_p->c_cflag |= CS8;

cfgetospeed() 返回termios_p 指向的termios 结构中存储的输出波特率 

cfsetospeed() 设置termios_p 指向的termios 结构中存储的输出波特率为speed。取值必须是以下常量之一: 
B0       B50       B75       B110       B134        B150       B200       B300       B600       B1200       B1800       B2400       B4800       B9600       B19200        B38400       B57600       B115200        B230400
其中:零值 B0 用来中断连接。如果指定了 B0,不应当再假定存在连接。通常,这样将断开连接。CBAUDEX是一个掩码,指示高于POSIX.1 定义的速度的那一些(57600 及以上)。因此,B57600& CBAUDEX 为非零。 

cfgetispeed() 返回 termios 结构中存储的输入波特率。 

cfsetispeed() 设置 termios 结构中存储的输入波特率为 speed。如果输入波特率被设为0,实际输入波特率将等于输出波特率。

RETURNVALUE 返回值
cfgetispeed()
返回termios 结构中存储的输入波特率。 

cfgetospeed()返回 termios 结构中存储的输出波特率。 
其他函数返回: 0(成功)或-1(失败),并且为 errno 置值来指示错误。 
注意:tcsetattr()返回成功,如果任何所要求的修改可以实现的话。因此,当进行多重修改时,应当在这个函数之后再次调用tcgetattr() 来检测是否所有修改都成功实现

 

实例:

1.关闭终端回显,键盘输入的字符不会在终端窗口显示:

#include <stdio.h>

#include <stdlib.h>

#include <termios.h>

#include <unistd.h>

 

int main(void)

{

struct termios ts,ots;

char passbuf[1024];

tcgetattr(STDIN_FILENO,&ts); // STDIN_FILENO的值是1,表示标准输入的文件描述符

ots = ts;

ts.c_lflag &= ~ECHO; /* 关闭回终端回显功能*/

ts.c_lflag |= ECHONL;

tcsetattr(STDIN_FILENO,TCSAFLUSH,&ts); /* 应用新终端设置 */

fgets(passbuf,1024,stdin); /* 输入字符不会在终端显示 */

printf("you input character = %s/n",passbuf);

tcsetattr(STDIN_FILENO,TCSANOW,&ots); /* 恢复旧的终端设备 */

}

2.读取每一个字符

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <termios.h>

char *menu[] = {

    "a - add new record",

    "d - delete record",

    "q - quit",

    NULL,

};

int getchoice(char *greet, char *choices[], FILE *in, FILE *out);

int main()

{

    int choice = 0;

    FILE *input;

    FILE *output;

    struct termios initial_settings,new_settings;

    if (!isatty(fileno(stdout))) {

        fprintf(stderr,"You arenot a terminal, OK.\n");

    }

    input =fopen("/dev/tty", "r");

    output = fopen("/dev/tty","w");

    if(!input || !output) {

        fprintf(stderr, "Unableto open /dev/tty\n");

        exit(1);

    }

   tcgetattr(fileno(input),&initial_settings);

    new_settings = initial_settings;

    new_settings.c_lflag &=~ICANON;

    new_settings.c_lflag &=~ECHO;

    new_settings.c_cc[VMIN] = 1;

    new_settings.c_cc[VTIME] = 0;

    new_settings.c_lflag &=~ISIG;

    if(tcsetattr(fileno(input),TCSANOW, &new_settings) != 0) {

        fprintf(stderr,"couldnot set attributes\n");

    }

 

    do {

        choice =getchoice("Please select an action", menu, input, output);

        printf("You havechosen: %c\n", choice);

    } while (choice != 'q');

   tcsetattr(fileno(input),TCSANOW,&initial_settings);

    exit(0);

}

int getchoice(char *greet, char *choices[], FILE *in, FILE *out)

{

    int chosen = 0;

    int selected;

    char **option;

    do {

        fprintf(out, "Choice:%s\n",greet);

        option = choices;

        while(*option) {

            fprintf(out,"%s\n",*option);

            option++;

        }

        do {

            selected = fgetc(in);

        } while (selected == '\n' ||selected == '\r');

        option = choices;

        while(*option) {

            if(selected ==*option[0]) {

                chosen = 1;

                break;

            }

            option++;

        }

        if(!chosen) {

            fprintf(out,"Incorrect choice, select again\n");

        }

    } while(!chosen);

    return selected;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值