Linux下的getch()函数的改进版

网上找到的getch()函数源码如下:

#include <termios.h>
#include <unistd.h>
#include <stdio.h>
int getch(void) {
	struct termios tm, tm_old;
	int fd = STDIN_FILENO, c;
	if(tcgetattr(fd, &tm) < 0)
	return -1;
	tm_old = tm;
	cfmakeraw(&tm);
	if(tcsetattr(fd, TCSANOW, &tm) < 0)
	return -1;
	c = fgetc(stdin);
	if(tcsetattr(fd, TCSANOW, &tm_old) < 0)
	return -1;
	return c;
}


经测试,在Linux下无法正常使用方向键,其余键能正常识别,为了解决这问题,我利用了模拟实现的kbhit函数检测是否有多个键值,有的话,累加键值,具体如下:

int set_raw(int t)
{
	static struct termio tty ;
	struct termio tmp ;

	if (t) {
		ioctl(0,TCGETA,&tty) ;
		tmp = tty ;
		tmp.c_lflag &= ~(ICANON|ECHOPRT);
		tmp.c_cc[VMIN] = 1 ;
		tmp.c_cc[VTIME] = 0 ;
		ioctl(0,TCSETA,&tmp) ;
	}
	else {
		tty.c_lflag &= ~(ICANON|ECHO);
		ioctl(0,TCSETA,&tty);
	}
	return 0;
}
int kbhit(void)  
{  
	struct termios oldt, newt;  
	int ch;  
	int oldf;  
	set_raw(3);
	tcgetattr(STDIN_FILENO, &oldt);  
	newt = oldt;  
	newt.c_lflag &= ~(ICANON | ECHO);  
	tcsetattr(STDIN_FILENO, TCSANOW, &newt);  
	oldf = fcntl(STDIN_FILENO, F_GETFL, 0);  
	fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);  
	ch = getchar();  
	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);  
	fcntl(STDIN_FILENO, F_SETFL, oldf);  
	if(ch != EOF)  
	{  
		ungetc(ch, stdin);  
		return 1;
	}
	set_raw(0);
	return 0;  
} 


int getch(void)
{ 
	struct termios tm, tm_old; 
	int fd = STDIN_FILENO,c;
	input = 0;
	if(tcgetattr(fd, &tm) < 0) 
	return -1; 

	tm_old = tm; 

	tm.c_lflag &= ~(ICANON|ECHO|ISIG);
	if(tcsetattr(fd, TCSANOW, &tm) < 0) 
	return -1; 

	c = fgetc(stdin);
	if(kbhit()){ /* 如果还有下一个键值 */
		c += getch();
	}
	if(tcsetattr(fd,TCSANOW,&tm_old)<0) return -1;
	if(c == 3) exit(1); /*如果是Ctrl+C组合键,就强制终止程序*/
	return c; 
}

LCUI 项目中,使用的代码是这样的:

static struct termios tm, tm_old; 
static int fd = STDIN_FILENO;
int Set_Raw(int t)
{
	if (t > 0) {
		if(tcgetattr(fd, &tm) < 0) 
		return -1; 
		tm_old = tm; 

		tm.c_lflag &= ~(ICANON|ECHO);
		tm.c_cc[VMIN] = 1;
		tm.c_cc[VTIME] = 0;
		if(tcsetattr(fd, TCSANOW, &tm) < 0) 
		return -1; 
		printf("\033[?25l");/* 隐藏光标 */
	}
	else {
		printf("\e[?25h"); /* 显示光标 */
		if(tcsetattr(fd,TCSANOW,&tm_old)<0) return -1;
	}
	return 0;
}

int Check_Key(void)  
{   
	struct termios oldt, newt;  
	int ch;  
	int oldf;  
	tcgetattr(STDIN_FILENO, &oldt);  
	newt = oldt;  
	newt.c_lflag &= ~(ICANON | ECHO);  
	tcsetattr(STDIN_FILENO, TCSANOW, &newt);  
	oldf = fcntl(STDIN_FILENO, F_GETFL, 0);  
	fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);  
	ch = getchar();  
	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);  
	fcntl(STDIN_FILENO, F_SETFL, oldf);  
	if(ch != EOF)  
	{
		ungetc(ch, stdin);  
		return 1;  
	} 
	return 0;
}

static int input,count = 0;

int Get_Key(void)
{ 
	++count;
	int k,c;
	k = fgetc(stdin);
	input += k; 
	if(Check_Key()){
		Get_Key();
	} 
	c = input;
	--count;
	if(count == 0) input = 0;
	if(c == 3) exit(1);
	return c; 
}

Set_Raw()函数用于初始化和恢复终端属性,参数t大于0时,初始化,否则,恢复终端属性。

Check_Key()函数和kbhit()函数一样,检测是否有按键输入。

Get_Key()函数用于获取按键输入的字符。



你可能感兴趣的:(c,linux,struct,测试,平台)