Chinaunix首页 | 论坛 | 博客
  • 博客访问: 19882494
  • 博文数量: 679
  • 博客积分: 10495
  • 博客等级: 上将
  • 技术积分: 9308
  • 用 户 组: 普通用户
  • 注册时间: 2006-07-18 10:51
文章分类

全部博文(679)

文章存档

2012年(5)

2011年(38)

2010年(86)

2009年(145)

2008年(170)

2007年(165)

2006年(89)

分类: LINUX

2008-12-10 17:44:01

结构

TermiosPOSIX规定的标准接口,它和System V的接口termio.类似。使用数据结构termios,在termios.h中定义,该文件还包含小量的函数调用。

使用termios.h中的函数调用时,要链接合适的函数库。根据系统,可能是标准的c库或者curses库。如有必要,编译的时候需要添加:-lcurses。老系统中甚至为-lncurses

模式有:

Input

Output

Control

Local

Special control characters

 

       最简单的termiosX/Open允许扩充。

#include

struct termios {

tcflag_t c_iflag;

tcflag_t c_oflag;

tcflag_t c_cflag;

tcflag_t c_lflag;

cc_t c_cc[NCCS];

};

 

         初始化termios

#include

int tcgetattr(int fd, struct termios *termios_p);

         重新配置终端接口:

#include

int tcsetattr(int fd, int actions, const struct termios *termios_p);

TCSANOW: Changes values immediately.

TCSADRAIN: Changes values when current output is complete.

TCSAFLUSH: Changes values when current output is complete, but discards any input currently

available and not yet returned in a read call.

       注意保存终端设置相当重要,一般需要程序来保存和恢复。

       更多的函数调用和模式请参考man手册或者POSIX or X/Open规范。

         最重要的模式是local mode,通过合适模式,前面的程序可以不输入回车。

     输入模式

 

决定输入来自于串口或者键盘。修改termios中的c_iflag,所有标识定义为宏,可以使用比特OR连接,后面的也是如此。宏定义如下:

BRKINT: Generate an interrupt when a break condition (loss of connection) is detected on the line

IGNBRK: Ignore break conditions on the line

ICRNL: Convert a received carriage return to a newline

IGNCR: Ignore received carriage returns

INLCR: Convert received newlines to carriage returns

IGNPAR: Ignore characters with parity errors

INPCK: Perform parity checking on received characters

PARMRK: Mark parity errors

ISTRIP: Strip (set to seven bits) all incoming characters

IXOFF: Enable software flow control on input

IXON: Enable software flow control on output

 

默认值一般可以满足所有需求。如果BRKINT nor IGNBRK 都没有设置,break状态是NULL (0x00)字符。

 

     输出模式

输出到串口或者屏幕。使用c_oflag,对用的宏:

OPOST: Turn on output processing

ONLCR: Convert any output newline to a carriage return/line feed pair

OCRNL: Convert any output carriage return to a newline

ONOCR: No carriage return output in column 0

ONLRET: A newline also does a carriage return

OFILL: Send fill characters to provide delays

OFDEL: Use DEL as a fill character, rather than NULL

NLDLY: Newline delay selection

CRDLY: Carriage return delay selection

TABDLY: Tab delay selection

BSDLY: Backspace delay selection

VTDLY: Vertical tab delay selection

FFDLY: Form feed delay selection

 

如果OPOST没有设置,其他标识都忽略。输出模式很少使用。

 

     控制模式

使用c_cflag:对应的宏:

CLOCAL: Ignore any modem status lines.

CREAD: Enable the receipt of characters.

CS5: Use five bits in sent or received characters.

CS6: Use six bits in sent or received characters.

CS7: Use seven bits in sent or received characters.

CS8: Use eight bits in sent or received characters.

CSTOPB: Use two stop bits per character, rather than one.

HUPCL: Hang up modem on close.

PARENB: Enable parity generation and detection.

PARODD: Use odd parity rather than even parity.

 

         If HUPCL is set, when the terminal driver detects that the last file descriptor referring to the terminal

has been closed, it will set the modem control lines to “hang-up” the line.

控制模式多用于连接modem的串口,通常,改终端配置比修改termios更快。

 

     本地模式

 

c_lflag用于控制终端的多种特征:

ECHO: Enable local echoing of input characters

ECHOE: Perform a Backspace, Space, Backspace combination on receiving ERASE

ECHOK: Perform erase line on the KILL character

ECHONL: Echo newline characters

ICANON: Enable canonical input processing (see the text following this list)

IEXTEN: Enable implementation-specific functions

ISIG: Enable signals

NOFLSH: Disable flush on queue

TOSTOP: Send background processes a signal on write attempts
        
使用最多的ECHOICANON

 

     特殊控制字符

c_cc数组,根据是否使用规范模式,它有2种不同的使用方法。(that is, the setting of the ICANON flag in the c_lflag member of termios).

Canonical模式:

VEOF: EOF character

VEOL: EOL character

VERASE: ERASE character

VINTR: INTR character

VKILL: KILL character

VQUIT: QUIT character

VSUSP: SUSP character

VSTART: START character

VSTOP: STOP character

 

non-canonical模式:

VINTR: INTR character

VMIN: MIN value

VQUIT: QUIT character

VSUSP: SUSP character

VTIME: TIME value

VSTART: START character

VSTOP: STOP character

 

-*字符

 

Character Description

INTR Causes the terminal driver to send a SIGINT signal to processes connected

to the terminal. We discuss signals in more detail in Chapter 11.

QUIT Causes the terminal driver to send a SIGQUIT signal to processes connected

to the terminal.

ERASE Causes the terminal driver to delete the last character on the line.

KILL Causes the terminal driver to delete the entire line.

EOF Causes the terminal driver to pass all characters on the line to the application

reading input. If the line is empty, a read call will return zero characters

as though a read had been attempted at the end of a file.

EOL Acts as a line terminator in addition to the more usual newline character.

SUSP Causes the terminal driver to send a SIGSUSP signal to processes connected

to the terminal. If your UNIX supports job control, the current

application will be suspended.

STOP Acts to “flow off”; that is, prevent further output to the terminal. It’s used

to support XON/XOFF flow control and is usually set to the ASCII XOFF

character, Ctrl+S.

START Restarts output after a STOP character, often the ASCII XON character.

 

-*TIME and MIN

         用于non-canonical中,控制输入。

MIN = 0 and TIME = 0:  立即返回

MIN = 0 and TIME > 0:能阅读或者10之一秒时返回

MIN > 0 and TIME = 0:读完MIN个字符再返回

MIN > 0 and TIME > 0:

 

         注意网络可能对时间产生的影响。

 

-*通过shell访问终端模式

查看终端:$ stty -a

$ stty sane

 

终端乱序的恢复方法:

一般使用$ stty sane,如果回车不能使用,可以改用:Ctrl+J

可以用保存恢复的方法:stty -g > save_stty,而后$ stty $(cat save_stty)。也可以使用Ctrl+J,如下:

save_stty=$(stty -g)

stty $save_stty

 

         最后的方法是选用其他终端。kill HUP 杀掉shellsttyshell登陆会重置。

 

-*通过命令行设置终端模式

         设置立即读入字符:$ stty -icanon min 1 time 0

         $ stty -echo

-*终端速度

      通过函数调用来实现,输入和输出分开处理。

#include

speed_t cfgetispeed(const struct termios *);

speed_t cfgetospeed(const struct termios *);

int cfsetispeed(struct termios *, speed_t speed);

int cfsetospeed(struct termios *, speed_t speed);

         针对termios,不是port。要用tcgetattr读取当前配置。使用上面的函数设置速率,再用tcsetattr写回termios

         常用值:

B0: Hang up the terminal

B1200: 1200 baud

B2400: 2400 baud

B9600: 9600 baud

B19200: 19200 baud

B38400: 38400 baud

         一些系统还定义了B57600, B115200, and B230400,是不可移植的。

-*附加函数

         这些函数直接操作文件描述符。

#include

int tcdrain(int fd);

int tcflow(int fd, int flowtype);

int tcflush(int fd, int in_out_selector);

tcdrain causes the calling program to wait until all queued output has been sent.

tcflow is used to suspend or restart output.

tcflush can be used to flush input, output, or both.

 

实例:读入password的时候禁用echo

        

# cat password.c

#include

#include

#include

 

#define PASSWORD_LEN 8

 

int main()

{

    struct termios initialrsettings, newrsettings;

    char password[PASSWORD_LEN + 1];

    tcgetattr(fileno(stdin), &initialrsettings);

    newrsettings = initialrsettings;

    newrsettings.c_lflag &= ~ECHO;

 

    printf("Enter password: ");

    if(tcsetattr(fileno(stdin), TCSAFLUSH, &newrsettings) != 0) {

        fprintf(stderr,"Could not set attributes\n");

    }

    else {

        fgets(password, PASSWORD_LEN, stdin);

        tcsetattr(fileno(stdin), TCSANOW, &initialrsettings);

        fprintf(stdout, "\nYou entered %s\n", password);

    }

    exit(0);

}

 

执行结果:

# ./password    

Enter password:

You entered 12345

 

即敲即读也是另外一种处理密码的方法。

 

实例:需要回车的菜单

 

# cat menu4.c

#include

#include

#include

#include

 

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 are not a terminal, OK.\n");

    }

 

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

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

    if(!input || !output) {

        fprintf(stderr, "Unable to 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,"could not set attributes\n");

    }

 

    do {

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

        printf("You have chosen: %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;

}

 

阅读(4106) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~