UNIX_C 环境下实现输入一个字符,不用回车直接输入功能(类型windows下_getch(void)函数)
/*
int getch ( void );
输入流获取一个信号当键盘输入一个字符时,
不用回车不会会写,直接读取输入的字符并继续运行
//linux 标准头文件库
#include <unistd.h>
#include <sys/ioctl.h>
#include <termios.h>
//windows 标准头文件库
#include <conio.h>
//调用函数
int ch = getch();
*/
#ifdef WIN32
//windows 默认函数
//int __cdecl _getch(void);
#else
//linux 环境下代码
int getch(void)
{
struct termios term_old;
ioctl( STDIN_FILENO, TCGETS, &term_old );
struct termios term_new = term_old;
term_new.c_lflag &= ~( ECHO | ICANON ); //取消会写与回车
ioctl( STDIN_FILENO, TCSETS, &term_new );
int ch = getchar();
ioctl(STDIN_FILENO, TCSETS, &term_old);
return ch;
}
</pre><pre code_snippet_id="1748202" snippet_file_name="blog_20160706_1_4593356" name="code" class="html">
<span style="font-size:18px;color:#ff0000;"><strong>编程实践教程》一书,里面有较详细的讲解,现将以上技巧如果实现及代码优化如下,还会不断改进</strong></span>
终端规范模式开启于关闭,使得缓冲和编辑失效
#include <termios.h>
#include<unistd.h>
int tcgetattr(int fd, structtermios *termios_p);
参 1:设备终端的文件描述符:0——标准输入,1——标准输出,2——标准错误
参 2:struct termios original_mode{
……
tcflag_t c_lflag; //本地模式标志,控制终端编辑功能
cc_t c_cc[NCCS];
};
c_lflag:ICANON —— 使用标准输入模式
eg:original_mode.c_lflag&= ~ICANON —— 去除标准输入模式
ECHO —— 回显功能
eg:original_mode.c_lflag&= ~ECHO —— 关闭回显功能
c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,如输入结束符等
NCCS: VMIN —— 非规范模式读取时的最小字符数
eg:original_mode.c_c[VMIN] =1
功能:用于获取与终端相关的参数,返回的结果保存在termios结构体中
int tcsetattr(int fd, int optional_actions, const struct termios*termios_p);
参 1:fd为打开的终端文件描述符,一般给 0;
参 2:optional_actions用于控制修改起作用的时间
* TCSANOW: 不等数据传输完毕就立即改变属性
参 3:而结构体termios_p中保存了要修改的参数
返回:函数在成功的时候返回0,失败的时候返回-1
功能:用于设置终端参数参数参数
//终端规范模式的关闭与开启
//实现缓冲和编辑失效
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
int tty_mode( int flg )
{
static struct termios mode;
if( 0 == flg )
{
//获取
if( !0 == tcgetattr(0, &mode) )
{
perror("tcgetattr error");
return -1;
}
}
else if( 1 == flg )
{
//设置
if( -1 == tcsetattr(0, TCSANOW, &mode) )
{
perror("tcgetattr error");
return -1;
}
}
else
{
return -1;
}
return 0;
}
int set_tty_mode(void)
{
struct termios new_mode;
//获取当前终端参数信息
if( !0 == tcgetattr(0, &new_mode))
{
perror("tcgetattr error");
return -1;
}
//去除标准输入模式
new_mode.c_lflag &= ~ICANON;
//关闭回显功能
new_mode.c_lflag &= ~ECHO;
//非规范模式下读取一个字符
new_mode.c_cc[VMIN] = 1;
if(-1 == tcsetattr(0, TCSANOW, &new_mode) )
{
perror("tcstattr error");
return -1;
}
return 0;
}
int choose( void )
{
printf("是否继续输入<Y/N>:");
char c = getchar();
switch(c)
{
case 'Y':
case 'y':
printf("\n");
printf("将继续输入!\n");
return 0;
case 'N':
case 'n':
printf("\n");
printf("将退出程序!\n");
return 0;
default:
return -1;
}
}
//当exit退出时将调用次函数恢复当前值
void atexit_function( void )
{
int res = tty_mode(1); //还原终端相关参数信息
if( -1 == res )
{
printf("终端设置失败!\n");
exit(1);
}
exit(1);
}
//或signal SIGINT信号将激活此函数
void signal_function( int signum )
{
int res = tty_mode(1); //还原终端相关参数信息
if( -1 == res )
{
printf("终端设置失败!\n");
exit(1);
}
exit(1);
}
int main( void )
{
atexit( atexit_function );
if( SIG_ERR == signal(SIGINT, signal_function) )
{
perror("signale error");
_Exit(1);
}
int res = tty_mode(0); //获取终端相关参数信息
if( -1 == res )
{
printf("终端获取失败!\n");
_Exit(1);
}
//设置终端非规范模式
res = set_tty_mode();
res = choose();
if(-1 == res )
{
printf("选择失败!\n");
exit(1);
}
}