Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

getch() and kbhit()

219 views
Skip to first unread message

NiTrOgEn

unread,
Jan 1, 2001, 11:21:18 AM1/1/01
to
List,

How can I use getch() and kbhit() from conio.h? I know that conio.h is
DOS specific, but which ones are used in Linux for that purpose? I read
that ncurses package has it....is it true? Where can I get it? How do
I use it?

Thank you,
Nitrogen,
cold...@uol.com.br

=+--+==+--+==+--+==+--+==+--+=+--+=
+ I'll see you on the other side. +
=+--+==+--+==+--+==+--+==+--+=+--+=


Sent via Deja.com
http://www.deja.com/

Erik Max Francis

unread,
Jan 1, 2001, 2:19:42 PM1/1/01
to
NiTrOgEn wrote:

> How can I use getch() and kbhit() from conio.h? I know that conio.h is
> DOS specific, but which ones are used in Linux for that purpose?

curses is usually used in UNIX/Linux where conio would be under DOS.

> I read
> that ncurses package has it....is it true? Where can I get it? How do
> I use it?

It is almost certainly a part of your standard installation.

man curses
man ncurses

--
Erik Max Francis / m...@alcyone.com / http://www.alcyone.com/max/
__ San Jose, CA, US / 37 20 N 121 53 W / ICQ16063900 / &tSftDotIotE
/ \ War is a continuation of policy by other means.
\__/ Karl von Clausewitz
Official Buh rules / http://www.alcyone.com/max/projects/cards/buh/
The official rules to the betting card game, Buh.

J. Otto Tennant

unread,
Jan 1, 2001, 9:40:19 PM1/1/01
to
NiTrOgEn <cold...@uol.com.br> writes:

>List,

>How can I use getch() and kbhit() from conio.h? I know that conio.h is
>DOS specific, but which ones are used in Linux for that purpose? I read
>that ncurses package has it....is it true? Where can I get it? How do
>I use it?

Curses is a pretty big package to use just to find out if someone has
pressed a key.

Think about using the *select*(2) system call instead. That system
call is a bit tricky to use, but it comes much closer to the DOS
kbhit than does curses.

(I wonder if one could implement kbhit using *select*? It probably
would not be too hard, but I think it would have to be surrounded
with a lot of caveats for general use.
--
J.Otto Tennant jo...@pobox.com
Forsan et haec olim meminisse juvabit.
Charter Member of the Vast Right Wing Conspiracy

Floyd Davidson

unread,
Jan 1, 2001, 11:26:05 PM1/1/01
to
j...@visi.com (J. Otto Tennant) wrote:
>NiTrOgEn <cold...@uol.com.br> writes:
>
>>List,
>
>>How can I use getch() and kbhit() from conio.h? I know that conio.h is
...

>Curses is a pretty big package to use just to find out if someone has
>pressed a key.
...

Curses is wonderful, but it is indeed a bit much for many
situations. Below is an example of how to code getch() and
kbhit() functionality for POSIX.

/*
* kbhit(), a keyboard lookahead monitor
* getch(), a blocking single character input from stdin
*
* Plus a demo main() to illustrate usage.
*/

#include <stdio.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>

int getch(void);
int kbhit(void);

#define CMIN 1

#ifdef CTIME
#undef CTIME
#endif

#define CTIME 1

/*
* kbhit() -- a keyboard lookahead monitor
*
* returns the number of characters available to read.
*/
int
kbhit(void)
{
int cnt = 0;
int error;
static struct termios Otty, Ntty;

tcgetattr(0, &Otty);
Ntty = Otty;

Ntty.c_iflag = 0; /* input mode */
Ntty.c_oflag = 0; /* output mode */
Ntty.c_lflag &= ~ICANON; /* raw mode */
Ntty.c_cc[VMIN] = CMIN; /* minimum time to wait */
Ntty.c_cc[VTIME] = CTIME; /* minimum characters to wait for */

if (0 == (error = tcsetattr(0, TCSANOW, &Ntty))) {
struct timeval tv;
error += ioctl(0, FIONREAD, &cnt);
error += tcsetattr(0, TCSANOW, &Otty);

/* throw in a miniscule time delay */
tv.tv_sec = 0;
tv.tv_usec = 100;
select(1, NULL, NULL, NULL, &tv);
}

return (error == 0 ? cnt : -1 );
}

/*
* 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
* existing buffered input before blocking.
*
*/
int
getch(void)
{
char ch;
int error;
static struct termios Otty, Ntty;

fflush(stdout);
tcgetattr(0, &Otty);
Ntty = Otty;

Ntty.c_iflag = 0; /* input mode */
Ntty.c_oflag = 0; /* output mode */
Ntty.c_lflag &= ~ICANON; /* line settings */

#if 1
/* disable echoing the char as it is typed */
Ntty.c_lflag &= ~ECHO; /* disable echo */
#else
/* enable echoing the char as it is typed */
Ntty.c_lflag |= ECHO; /* enable echo */
#endif

Ntty.c_cc[VMIN] = CMIN; /* minimum time to wait */
Ntty.c_cc[VTIME] = CTIME; /* minimum chars to wait for */

#if 1
/*
* use this to flush the input buffer before blocking for new input
*/
#define FLAG TCSAFLUSH
#else
/*
* use this to return a char from the current input buffer, or block if
* no input is waiting.
*/
#define FLAG TCSANOW

#endif

if (0 == (error = tcsetattr(0, FLAG, &Ntty))) {
error = read(0, &ch, 1 ); /* get char from stdin */
error += tcsetattr(0, FLAG, &Otty); /* restore old settings */
}

return (error == 1 ? (int) ch : -1 );
}


/*
* a cutsie main() to demo how getch() and kbhit() work.
*/

#include <ctype.h>

int
main(void)
{
int ch, cnt;
static struct termios Otty, Ntty;

tcgetattr(0, &Otty);
Ntty = Otty;
Ntty.c_lflag &= ~ECHO;

printf("You must enter 10 characters to get\nthis program to continue: ");
fflush(stdout);
/* collect 10 characters */
while (1) {
if (10 <= (cnt = kbhit())) {
break;
}
}

tcsetattr(0, TCSANOW, &Ntty); /* disable echoing of further input */
printf("\nSTOP!");
fflush(stdout);
printf("\nNow type <Enter> to continue!");
fflush(stdout);
ch = getchar();
tcsetattr(0, TCSANOW, &Otty); /* enable echoing of further input */
printf("\n\nThe first five characters are: \"");
/*
* print a few chars, note that calling getch() will flush
* remaining buffered input.
*/
cnt = 4;
do {
printf("%c", ch);
ch = getchar();
} while (--cnt);
printf("%c\"\n\n", ch);

printf("\n\n *** Demo Menu ***\n\n");
printf(" Option Action\n");
printf(" A Exit and print an A word\n");
printf(" B Exit and print a B word\n");
printf(" C Exit and print a C word\n");
printf("\n Enter your choice: ?\b");
fflush(stdout);

while(1) {
switch (ch = getch()) {
case 'a': case 'A':
printf("%c\n\nThat is an *awesome* function!\n", toupper(ch));
break;
case 'b': case 'B':
printf("%c\n\nThat is a *beneficial* function!\n", toupper(ch));
break;
case 'c': case 'C':
printf("%c\n\nThat is a *critical* function!\n", toupper(ch));
break;
default:
continue;
}
break;
}
return 0;
}


--
Floyd L. Davidson <http://www.ptialaska.net/~floyd>
Ukpeagvik (Barrow, Alaska) fl...@barrow.com

Dave Blake

unread,
Jan 1, 2001, 10:44:49 PM1/1/01
to
J. Otto Tennant <j...@visi.com> wrote:

> Curses is a pretty big package to use just to find out if
> someone has pressed a key.
>
> Think about using the *select*(2) system call instead. That
> system call is a bit tricky to use, but it comes much closer
> to the DOS kbhit than does curses.

> (I wonder if one could implement kbhit using *select*? It probably
> would not be too hard, but I think it would have to be surrounded
> with a lot of caveats for general use.

It is pretty simple. Change terminal io characteristics
to
ntermios.c_cc[VMIN] = 0;
ntermios.c_cc[VTIME] = 0;
tcsetattr(0, TCSADRAIN, &ntermios);


Then read a char from stdin. If it is EOF, the a key has not
been entered. Call select to wait for stdin

Something like this

int stdinready ()
{
fd_set set;
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (STDIN_FILENO, &set);
/* `select' returns 0 if timeout, 1 if input available, -1 if error. */
return (select(2,&set, NULL, NULL,NULL));
}

ttgetc()
{
int c;
c = fgetc(stdin);
if ( c == EOF){
stdinready();
c = fgetc(stdin);
}
return(255 & c); /* 8BIT */
}


I'll leave it as an exercise to figure out required headers
and so libs.

--
Dave Blake
dbl...@phy.ucsf.edu

Kaz Kylheku

unread,
Jan 2, 2001, 5:19:32 AM1/2/01
to
On 2 Jan 2001 03:44:49 GMT, Dave Blake <dbl...@popper.ucsf.edu> wrote:
>ttgetc()
>{
> int c;
> c = fgetc(stdin);
> if ( c == EOF){
> stdinready();
> c = fgetc(stdin);

Better add: clearerr(stdin);

Jimi

unread,
Jan 2, 2001, 5:15:14 PM1/2/01
to
Those are really useful functions. Thanks a lot!

phil-new...@ipal.net

unread,
Jan 4, 2001, 10:45:05 PM1/4/01
to
On 2 Jan 2001 16:15:14 -0600 Jimi <ji...@soulhunter.com> wrote:

| Those are really useful functions. Thanks a lot!

Why do people insist on calling it "kbhit"?
Hitting a keyboard can cause damage.

--
-----------------------------------------------------------------
| Phil Howard - KA9WGN | Dallas | http://linuxhomepage.com/ |
| phil-...@ipal.net | Texas, USA | http://phil.ipal.org/ |
-----------------------------------------------------------------

Kaz Kylheku

unread,
Jan 5, 2001, 1:20:43 AM1/5/01
to
On Fri, 05 Jan 2001 03:45:05 -0000, phil-new...@ipal.net
<phil-new...@ipal.net> wrote:
>On 2 Jan 2001 16:15:14 -0600 Jimi <ji...@soulhunter.com> wrote:
>
>| Those are really useful functions. Thanks a lot!
>
>Why do people insist on calling it "kbhit"?
>Hitting a keyboard can cause damage.

Some hits cause damage, some don't. You can hit a cache. Hit a web
server. Hit the bottle. Hit the big time. Hit the road, Jack!

Victor Wagner

unread,
Jan 7, 2001, 3:54:13 PM1/7/01
to
phil-new...@ipal.net wrote:

: On 2 Jan 2001 16:15:14 -0600 Jimi <ji...@soulhunter.com> wrote:

: | Those are really useful functions. Thanks a lot!

: Why do people insist on calling it "kbhit"?
: Hitting a keyboard can cause damage.

using conio.h under DOS also can cause damage. Especially to programmer's
brains.

One need to learn that he either should write programs which are pure
command-line driven and do not prevent user from redirecing input,
or write full featured screen-interface using cursess, Turbo Vision,
cxl, slang or whatever.

conio.h is too low-level for second task and causes too much
interference with first.

--
The state of some commercial Un*x is more unsecure than any Linux box
without a root password...
-- Bernd Eckenfels

The Ghost In The Machine

unread,
Jan 8, 2001, 8:09:40 PM1/8/01
to
In comp.os.linux.development.apps, Dave Blake
<dbl...@popper.ucsf.edu>
wrote
on 2 Jan 2001 03:44:49 GMT
<slrn952jlh...@popper.ucsf.edu>:

>J. Otto Tennant <j...@visi.com> wrote:
>
>> Curses is a pretty big package to use just to find out if
>> someone has pressed a key.
>>
>> Think about using the *select*(2) system call instead. That
>> system call is a bit tricky to use, but it comes much closer
>> to the DOS kbhit than does curses.
>
>> (I wonder if one could implement kbhit using *select*? It probably
>> would not be too hard, but I think it would have to be surrounded
>> with a lot of caveats for general use.
>
>
>
>It is pretty simple. Change terminal io characteristics
>to
> ntermios.c_cc[VMIN] = 0;
> ntermios.c_cc[VTIME] = 0;
> tcsetattr(0, TCSADRAIN, &ntermios);

The manpage for cfmakeraw -- which probably isn't POSIX -- also
suggests the following:

ntermios.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
ntermios.c_oflag &= ~OPOST;
ntermios.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
ntermios.c_cflag &= ~(CSIZE|PARENB);
ntermios.c_cflag |= CS8;

With these modifications, a test program works, although for some
reason stdout is not translating newlines -- probably not surprising
in light of c_lflag in the above. :-)

>
>
>Then read a char from stdin. If it is EOF, the a key has not
>been entered. Call select to wait for stdin
>
>Something like this
>
> int stdinready ()
> {
> fd_set set;
> /* Initialize the file descriptor set. */
> FD_ZERO (&set);
> FD_SET (STDIN_FILENO, &set);
> /* `select' returns 0 if timeout, 1 if input available, -1 if error. */
> return (select(2,&set, NULL, NULL,NULL));
> }
>
>ttgetc()
>{
> int c;
> c = fgetc(stdin);
> if ( c == EOF){
> stdinready();
> c = fgetc(stdin);
> }
> return(255 & c); /* 8BIT */
>}
>
>
>I'll leave it as an exercise to figure out required headers
>and so libs.

No libraries are required.

These headers work:

#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>

although whether they're minimal or not, I can't say right now.

>
>--
>Dave Blake
>dbl...@phy.ucsf.edu


--
ew...@aimnet.com -- insert random misquote here
up 97 days, 1:35, running Linux.

0 new messages