标题
请问在linux环境下应该能使用kbhit这个函数吗?[zt]
clq
浏览(0) +
2008-04-12 18:01:49 发表
编辑
关键字:
请问在linux环境下应该能使用kbhit这个函数吗?
来自 http://www.lslnet.com/linux/dosc1/63/linux-413619.htm
Re: 请问在linux环境下应该能使用kbhit这个函数吗?
c的标准函数,应该没有什么问题
Re: 请问在linux环境下应该能使用kbhit这个函数吗?
我本来也是这么想的。可是在我的RH7。2中我用了这个函数,并加了头文件conio.h,可是我的系统根本就不认这个头文件啊。更不用说用这个函数了。请问有办法解决吗
Re: 请问在linux环境下应该能使用kbhit这个函数吗?
發信人: lmy@cis_nctu (Daemon of Andromeda), 信區: programming
標 題: kbhit() in UNIX 補充 (was: Re: 一些問題 (UNIX C))
發信站: 交大資科_BBS (Mar 20 15:30:37 1995)
轉信站: cis_nctu
==>[作者]: lmy@cis_nctu(Daemon of Andromeda) 在 programming 討論區中提到:
> 若不用 select, 用 signal SIGIO 也可以達成. 但純用 ioctl 的話,
> 我看了一下 linux kernel 的 source, 發現 linux 可以這樣用
> kbhit()
> {
> int i;
> ioctl(0, TIOCINQ, &i);
> return i!=0;
> }
> 不過 porting 到 Sun 上就掛了... 顯然不太 standard...
今天碰巧發現了完全符合 wdlin 兄規定只用 ioctl 的規格的 kbhit()
並且可 porting (at least on SunOS, linux)
#include
kbhit()
{
int n;
ioctl(0, FIONREAD, &n);
return n;
}
Re: 请问在linux环境下应该能使用kbhit这个函数吗?
按楼上的方法好像不行,在dos下,kbhit只要按了键盘就能马上返回键值,而楼上的方法要回车才能返回。
Re: 请问在linux环境下应该能使用kbhit这个函数吗?
这和终端模式有关,缺省的是行模式,所以要回车。改成raw模式即可。
Re: 请问在linux环境下应该能使用kbhit这个函数吗?
在程序里如何该成raw模式并且在程序退出时恢复?
Re: 请问在linux环境下应该能使用kbhit这个函数吗?
可以用
system("stty raw");
...
system("stty cooked");
来切换。
看看置顶贴
struct termios new_settings;
tcgetattr(0,&stored_settings);
new_settings = stored_settings;
/* Disable canonical mode, and set buffer size to 1 byte */
new_settings.c_lflag &= (~ICANON);
new_settings.c_cc[VTIME] = 0;
new_settings.c_cc[VMIN] = 1;
tcsetattr(0,TCSANOW,&new_settings);
19.5 从stdin立即获取按键
19.5 从stdin立即获取按键
Q: Linux/C编程环境,从标准输入stdin读取内容时,有无办法立即获取按键,而不
必等待换行。事实上我需要MS-DOS下的kbhit()、getch()函数。
有些人总是建议进入(n)curses环境,可我不想使用这种多此一举的技术。
A: Floyd Davidson
我们就作者所提供的原始代码进行了一些移植、修正,手头系统有限,未做更广泛的
可移植性测试。
--------------------------------------------------------------------------
/*
* For x86/Linux Kernel 2.4.7-10
* gcc -DLinux -Wall -pipe -O3 -o input_demo input_demo.c
*
* For x86/FreeBSD 4.5-RELEASE
* gcc -DFreeBSD -Wall -pipe -O3 -o input_demo input_demo.c
*
* For SPARC/Solaris 8
* gcc -DSolaris -Wall -pipe -O3 -o input_demo input_demo.c
*
* kbhit() -- a keyboard lookahead monitor
* getch() -- a blocking single character input from stdin
*
* Plus a demo main() to illustrate usage.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef Solaris
#include
#endif
#undef TERMIOSECHO
#define TERMIOSFLUSH
/*
* getch() -- a blocking single character input from stdin
*
* Returns a character, or -1 if an input error occurs
*
* Conditionals allow compiling with or without echoing of the input
* characters, and with or without flushing pre-existing buffered input
* before blocking.
*/
static int getch ( void )
{
struct termios old_termios, new_termios;
int error;
char c;
fflush( stdout );
tcgetattr( 0, &old_termios );
new_termios = old_termios;
/*
* raw mode, line settings
*/
new_termios.c_lflag &= ~ICANON;
#ifdef TERMIOSECHO
/*
* enable echoing the char as it is typed
*/
new_termios.c_lflag |= ECHO;
#else
/*
* disable echoing the char as it is typed
*/
new_termios.c_lflag &= ~ECHO;
#endif
#ifdef TERMIOSFLUSH
/*
* use this to flush the input buffer before blocking for new input
*/
#define OPTIONAL_ACTIONS TCSAFLUSH
#else
/*
* use this to return a char from the current input buffer, or block
* if no input is waiting
*/
#define OPTIONAL_ACTIONS TCSANOW
#endif
/*
* minimum chars to wait for
*/
new_termios.c_cc[VMIN] = 1;
/*
* minimum wait time, 1 * 0.10s
*/
new_termios.c_cc[VTIME] = 1;
error = tcsetattr( 0, OPTIONAL_ACTIONS, &new_termios );
if ( 0 == error )
{
/*
* get char from stdin
*/
error = read( 0, &c, 1 );
}
/*
* restore old settings
*/
error += tcsetattr( 0, OPTIONAL_ACTIONS, &old_termios );
return( error == 1 ? ( int )c : -1 );
} /* end of getch */
/*
* kbhit() -- a keyboard lookahead monitor
*
* returns the number of characters available to read
*/
static int kbhit ( void )
{
struct timeval tv;
struct termios old_termios, new_termios;
int error;
int count = 0;
tcgetattr( 0, &old_termios );
new_termios = old_termios;
/*
* raw mode
*/
new_termios.c_lflag &= ~ICANON;
/*
* disable echoing the char as it is typed
*/
new_termios.c_lflag &= ~ECHO;
/*
* minimum chars to wait for
*/
new_termios.c_cc[VMIN] = 1;
/*
* minimum wait time, 1 * 0.10s
*/
new_termios.c_cc[VTIME] = 1;
error = tcsetattr( 0, TCSANOW, &new_termios );
tv.tv_sec = 0;
tv.tv_usec = 100;
/*
* insert a minimal delay
*/
select( 1, NULL, NULL, NULL, &tv );
error += ioctl( 0, FIONREAD, &count );
error += tcsetattr( 0, TCSANOW, &old_termios );
return( error == 0 ? count : -1 );
} /* end of kbhit */
int main ( int argc, char * argv[] )
{
struct termios old_termios, new_termios;
int count;
int c;
tcgetattr( 0, &old_termios );
printf( "You must enter 10 characters to get this program to continue:" );
fflush( stdout );
/*
* collect 10 characters
*/
for ( count = kbhit(); count < 10; count = kbhit() )
{
if ( -1 == count )
{
return( EXIT_FAILURE );
}
}
new_termios = old_termios;
/*
* disable echoing of further input
*/
new_termios.c_lflag &= ~ECHO;
tcsetattr( 0, TCSANOW, &new_termios );
printf( "\nStop, now type to continue" );
fflush( stdout );
c = getchar();
/*
* enable echoing of further input
*/
tcsetattr( 0, TCSANOW, &old_termios );
printf( "\nThe first five characters are: [" );
/*
* print a few chars
*/
for ( count = 0; count < 4; count++ )
{
printf( "%c", ( char )c );
c = getchar();
}
printf( "%c]\n\n", ( char )c );
printf( "****** Demo Menu ******\n\n" );
printf( "Option Action\n" );
printf( " A Action_A\n" );
printf( " B Action_B\n" );
printf( " C Action_C\n" );
printf( " Q Exit\n\n" );
printf( "Enter your choice: [ ]\b\b" );
fflush( stdout );
/*
* note that calling getch() will flush remaining buffered input
*/
switch ( c = getch() )
{
case 'a':
case 'A':
printf( "%c\nAction_A\n", ( char )toupper( ( int )c ) );
break;
case 'b':
case 'B':
printf( "%c\nAction_B\n", ( char )toupper( ( int )c ) );
break;
case 'c':
case 'C':
printf( "%c\nAction_C\n", ( char )toupper( ( int )c ) );
break;
case 'q':
case 'Q':
printf( "%c\nExit\n", ( char )toupper( ( int )c ) );
break;
default:
printf( "%c\n", ( char )toupper( ( int )c ) );
break;
}
tcsetattr( 0, TCSANOW, &old_termios );
return( EXIT_SUCCESS );
} /* end of main */
--------------------------------------------------------------------------
D: 小四
c_cc[VTIME]以0.10秒为单位指定一个字节间的读取超时,所对应的计时器在接收到
第一个字节之后才启动,因此c_cc[VMIN]为1的时候,c_cc[VTIME]是多少都无所谓。
关于这方面的详细讨论参看APUE 11.11小节。
input_demo.c:main()中第一个getchar()调用,其本意是在"规范模式"下阻塞,等待
一个换行。SPARC/Solaris 8下语义与x86/Linux Kernel 2.4.7-10、x86/FreeBSD
4.5-RELEASE不同,在此处未能阻塞住,我怀疑是该版本实现上的一个BUG。
clq
Linux下kbhit()的实现
我们知道,在windows下有个键盘测试函数,int kbhit(void)。使用该函数需要包含头文件conio.h。执行时,kbhit测试是否有键盘按键按下,若有则返回非零值,否则返回零。
在Unix/Linux下,并没有提供这个函数。在linux下开发控制台程序时,有时会遇到检测键盘是否有被按下的情况,这时就需要自己编写kbhit()实现的程序了。下面是kbhit在Unix/Linux下的一个实现。用到了一种终端操作库termios。
下面是头文件kbhit.h:
#ifndef KBHITh
#define KBHITh
void init_keyboard(void);
void close_keyboard(void);
int kbhit(void);
int readch(void);
#endif
下面式源程序kbhit.c:
#include "kbhit.h"
#include
#include // for read()
static struct termios initial_settings, new_settings;
static int peek_character = -1;
void init_keyboard()
{
tcgetattr(0,&initial_settings);
new_settings = initial_settings;
new_settings.c_lflag &= ~ICANON;
new_settings.c_lflag &= ~ECHO;
new_settings.c_lflag &= ~ISIG;
new_settings.c_cc[VMIN] = 1;
new_settings.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &new_settings);
}
void close_keyboard()
{
tcsetattr(0, TCSANOW, &initial_settings);
}
int kbhit()
{
unsigned char ch;
int nread;
if (peek_character != -1) return 1;
new_settings.c_cc[VMIN]=0;
tcsetattr(0, TCSANOW, &new_settings);
nread = read(0,&ch,1);
new_settings.c_cc[VMIN]=1;
tcsetattr(0, TCSANOW, &new_settings);
if(nread == 1)
{
peek_character = ch;
return 1;
}
return 0;
}
int readch()
{
char ch;
if(peek_character != -1)
{
ch = peek_character;
peek_character = -1;
return ch;
}
read(0,&ch,1);
return ch;
}
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.