登录 用户中心() [退出] 后台管理 注册
   
您的位置: 首页 >> 程序员学前班[不再更新,只读] >> 主题: 请问在linux环境下应该能使用kbhit这个函数吗?[zt]     [回主站]     [分站链接]
标题
请问在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
2008-4-12 18:04:11 发表 编辑

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;
}


总数:1 页次:1/1 首页 尾页  
总数:1 页次:1/1 首页 尾页  


所在合集/目录



发表评论:
文本/html模式切换 插入图片 文本/html模式切换


附件:



NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.

Copyright © 2005-2020 clq, All Rights Reserved
版权所有
桂ICP备15002303号-1