转载地址:http://blog.csdn.net/sdkhy0808/article/details/36172009
<termios.h>
<unistd.h>int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
getch的代码如下:
static int getch(void)
{struct termios oldt,newt;
int ch;
if (!isatty(STDIN_FILENO)) {
fprintf(stderr, "this problem should be run at a terminal\n");
exit(1);
}
// save terminal setting
if(tcgetattr(STDIN_FILENO, &oldt) < 0) {
perror("save the terminal setting");
exit(1);
}
// set terminal as need
newt = oldt;
newt.c_lflag &= ~( ICANON | ECHO );
if(tcsetattr(STDIN_FILENO,TCSANOW, &newt) < 0) {
perror("set terminal");
exit(1);
}
ch = getchar();
// restore termial settingif(tcsetattr(STDIN_FILENO,TCSANOW,&oldt) < 0) {
perror("restore the termial setting");
exit(1);
}
return ch;
}
刚开始不明白,这个函数最终返回的是ch,而ch=getchar(),与getch函数中的其他均无关系,为何不只用getchar,其他的到底什么作用?后来我逐个实验了一下,才知道其中的区别。
如果只用getchar的话,运行程序时,按下一个按键,比如 ESC,那么界面上会显示一个乱码,并且不会立即起作用,只有按下Enter键才会起作用。而用getch中的几个函数,可以设置终端输入的属性,比如不让字符在界面上显示,输入字符立即起作用。下面就对其中的3个函数的作用进行分析。
1、isatty(STDIN_FILENO) 判断是否为终端输入,如果是,则返回1,否则返回0。
当然也可以判断输出,那么函数写为isatty(STDOUT_FILENO) 。
关于isatty的参数,详解:
对一个进程预定义了三个流,并且这三个流可以自动地被进程使用,它们是:标准输入、标准输出和标准出错,即TDIN_FILENO、STDOUT_FILENO和STDERR_FILENO。
2、tcgetattr(STDIN_FILENO, &oldt) 用来获取终端输入的属性,并保存在结构体oldt中。
分析:获取终端输入属性的目的在于后面的恢复。
3、tcsetattr(STDIN_FILENO,TCSANOW, &newt) 用来设置终端输入的属性,通过结构体newt。
1)第二个参数可以取以下3个值:
TCSANOW:不等数据传输完毕就立即改变属性。
TCSADRAIN:等待所有数据传输结束才改变属性。
TCSAFLUSH:清空输入输出缓冲区才改变属性。
可以按照自己的需要进行设置。
2)结构体 termios newt有以下几个成员
{c_iflag:输入模式标志,控制终端输入方式
c_oflag:输出模式标志,控制终端输出方式
c_cflag:控制模式标志,指定终端硬件控制信息
c_lflag:本地模式标志,控制终端编辑功能}
这里只用到了c_lflag,c_lflag的参数如下:
ISIG:当输入INTR、QUIT、SUSP或DSUSP时,产生相应的信号
ICANON:使用标准输入模式
XCASE:在ICANON和XCASE同时设置的情况下,终端只使用大写。
ECHO :显示输入字符
ECHOE:如果ICANON同时设置,ERASE将删除输入的字符
ECHOK:如果ICANON同时设置,KILL将删除当前行
ECHONL:如果ICANON同时设置,即使ECHO没有设置依然显示换行符
ECHOPRT:如果ECHO和ICANON同时设置,将删除打印出的字符(非POSIX)
TOSTOP:向后台输出发送SIGTTOU信号
上述代码中,用的是newt &= ~(ICANON | ECHO);那么,就不使用标准输入模式,不显示输入字符。
如果想采用标准输入模式,显示输入字符,那么newt = ICANON | ECHO。
4、tcsetattr(STDIN_FILENO,TCSANOW,&oldt) 恢复终端输入属性。
刚开始不明白这句的意义,于是实验了一下。如果去掉这句的话,发现当我程序退出后,输入命令输入不进去,其实已经输入进去了,只是没有显示。因为现在的输入属性是newt新设置的,而不是原来的oldt,所以必须得恢复。