termios的例子

来源:互联网 发布:php门户网站 编辑:程序博客网 时间:2024/06/06 12:52

linux程序设计 5.4节

先看一个menu.c函数

#include <unistd.h>
#include <stdio.h>
#include <termios.h>
char *menu[] = {"a - add new recode", "b - delete recode", "q - quit", "NULL"};
int getchoice(char *greet, char *choices[], FILE *in, FILE *out);
int main()
{
    int choice = 0;
    FILE *in;  //两个文件描述符,用来连接到终端(将终端作为文件进行操作)
    FILE *out;
        
    if( !isatty(fileno(stdout)) ) {  //判断输出流是否连接到终端
        fprintf(stderr, "You not a terminal! \n");
    }
    
    in = fopen("/dev/tty", "r");  //打开连接到终端的读描述符
    out = fopen("/dev/tty", "w");  //打开连接到终端的写描述符
    if( !in || ! out){
        fprintf(stderr, "Unable to open .dev/tty \n");
        return -1;
    }
    
    do{
        choice = getchoice("Please select an action", menu, in , out);
        printf("You have chosen: %c \n\n", choice);
    }while( 'q' != choice );
    return 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++;
        }
        fprintf(out, " \n");
        
        do {
            selected = fgetc(in);
        }while('\n' == selected );  //标准输入模式下,回车符与换行符是相关联的,因此只需要检测其中任意一个即可
        
        option = choices;
        while(*option)
        {
            if( *option[0] == selected ){
                chosen = 1;
                break;
            }
            option++;
        }
        
        if( 1 != chosen ) {
            fprintf(out, "Incorrect choice, select again \n\n");
        }
                
    }while(!chosen);
    
    return selected;
}

该函数在标准输入模式下运行,当用户输入选项后需要键入回车,程序才会读取输入字符


要实现输入选项后,程序立即执行而不必等待回车的模式,我们可以对程序做以下修改

#include <unistd.h>
#include <stdio.h>
#include <termios.h>  //包含termios结构和相关函数的头文件

char *menu[] = {"a - add new recode", "b - delete recode", "q - quit", "NULL"};
int getchoice(char *greet, char *choices[], FILE *in, FILE *out);

int main()
{
    int choice = 0;
    FILE *in;
    FILE *out;
    struct termios initial_settings, new_settings;  //声明termios类型的结构体变量
        
    if( !isatty(fileno(stdout)) ){
        fprintf(stderr, "You not a terminal! \n");
    }
    
    in = fopen("/dev/tty", "r");
    out = fopen("/dev/tty", "w");
    if( !in || ! out){
        fprintf(stderr, "Unable to open .dev/tty \n");
        return -1;
    }
    tcgetattr(fileno(in), &initial_settings);  //获得默认的终端属性
    new_settings = initial_settings;
    new_settings.c_lflag &= ~ICANON;  //清除变量中由ICANON和ECHO标志定义的比特,将输入模式改为非标准模式
    new_settings.c_lflag &= ~ECHO;
    new_settings.c_cc[VMIN] = 1;  //MIN = 1, TIME = 0时,read()在有一个字符等待处理时就调用
    new_settings.c_cc[VTIME] = 0;
    if ( 0 != tcsetattr(fileno(in), TCSANOW, &new_settings)){  //使新的属性生效
        fprintf(stderr, "Could not set attributes \n");
    }    
    do{
        choice = getchoice("Please select an action", menu, in , out);
        printf("You have chosen: %c \n\n", choice);
    }while( 'q' != choice );
    tcsetattr(fileno(in), TCSANOW, &initial_settings);  //程序结束后,要记得恢复到原属性
    return 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++;
        }
        fprintf(out, " \n");
        do{
            selected = fgetc(in);
        }while('\n' == selected || '\r' == selected);  //非标准模式下,回车符和换行符之间的映射已经不存在,因此需要分别检测
        
        option = choices;
        while(*option)
        {
            if( *option[0] == selected ){
                chosen = 1;
                break;
            }
            option++;
        }
        if( 1 != chosen ){
            fprintf(out, "Incorrect choice, select again \n\n");
        }            
    }while(!chosen);
    return selected;
}