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


getch()函数源码如下:

[cpp]
  1. #include <termios.h>   
  2. #include <unistd.h>   
  3. #include <stdio.h>   
  4. int getch(void) {  
  5.     struct termios tm, tm_old;  
  6.     int fd = STDIN_FILENO, c;  
  7.     if(tcgetattr(fd, &tm) < 0)  
  8.     return -1;  
  9.     tm_old = tm;  
  10.     cfmakeraw(&tm);  
  11.     if(tcsetattr(fd, TCSANOW, &tm) < 0)  
  12.     return -1;  
  13.     c = fgetc(stdin);  
  14.     if(tcsetattr(fd, TCSANOW, &tm_old) < 0)  
  15.     return -1;  
  16.     return c;  
  17. }  

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

[cpp]
  1. int set_raw(int t)  
  2. {  
  3.     static struct termio tty ;  
  4.     struct termio tmp ;  
  5.   
  6.     if (t) {  
  7.         ioctl(0,TCGETA,&tty) ;  
  8.         tmp = tty ;  
  9.         tmp.c_lflag &= ~(ICANON|ECHOPRT);  
  10.         tmp.c_cc[VMIN] = 1 ;  
  11.         tmp.c_cc[VTIME] = 0 ;  
  12.         ioctl(0,TCSETA,&tmp) ;  
  13.     }  
  14.     else {  
  15.         tty.c_lflag &= ~(ICANON|ECHO);  
  16.         ioctl(0,TCSETA,&tty);  
  17.     }  
  18.     return 0;  
  19. }  
  20. int kbhit(void)    
  21. {    
  22.     struct termios oldt, newt;    
  23.     int ch;    
  24.     int oldf;    
  25.     set_raw(3);  
  26.     tcgetattr(STDIN_FILENO, &oldt);    
  27.     newt = oldt;    
  28.     newt.c_lflag &= ~(ICANON | ECHO);    
  29.     tcsetattr(STDIN_FILENO, TCSANOW, &newt);    
  30.     oldf = fcntl(STDIN_FILENO, F_GETFL, 0);    
  31.     fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);    
  32.     ch = getchar();    
  33.     tcsetattr(STDIN_FILENO, TCSANOW, &oldt);    
  34.     fcntl(STDIN_FILENO, F_SETFL, oldf);    
  35.     if(ch != EOF)    
  36.     {    
  37.         ungetc(ch, stdin);    
  38.         return 1;  
  39.     }  
  40.     set_raw(0);  
  41.     return 0;    
  42. }   
  43.   
  44.   
  45.   
  46. static int input;  
  47.   
  48.   
  49. int getch(void)  
  50. {   
  51.     struct termios tm, tm_old;   
  52.     int fd = STDIN_FILENO,c;  
  53.     input = 0;  
  54.     if(tcgetattr(fd, &tm) < 0)   
  55.     return -1;   
  56.   
  57.     tm_old = tm;   
  58.   
  59.     tm.c_lflag &= ~(ICANON|ECHO|ISIG);  
  60.     if(tcsetattr(fd, TCSANOW, &tm) < 0)   
  61.     return -1;   
  62.   
  63.     int k;  
  64.     input = fgetc(stdin);  
  65.     k = input;  
  66.     if(kbhit()){ /* 如果还有下一个键值 */  
  67.         input += getch();  
  68.     }  
  69.     if(tcsetattr(fd,TCSANOW,&tm_old)<0) return -1;  
  70.     c = input;  
  71.     if(c == 3) exit(1); /*如果是Ctrl+C组合键,就强制终止程序*/  
  72.     return c;   
  73. }  

本函数的代码仅在诺亚舟NP1500学习机里测试通过,并不保证在其它平台上也能正常执行。

相关内容