I'm looking throughout the Internet in search of some function that will read a key from keyboard without waiting for LF (like getch() from conio.h). Unfortunately I have to compile it with gcc using switches -ansi and -pedantic, which makes getch() useless to me. Maybe you know some other function that'll match standards?
Asked
Active
Viewed 1,702 times
2
-
Does `getchar` not do what you need? – more tension Oct 16 '12 at 19:13
-
1There's no portable way to do this. Make your own "portable" wrapper for each OS. – user541686 Oct 16 '12 at 20:02
-
As I wrote simple program using `getchar()`, it still waits for LF. Why is this so difficult? Was it so hard to just take one character from buffer? more difficult than take all of them after LF character? – Sushi271 Oct 16 '12 at 20:11
-
the problem is not that it is hard to take one character from the buffer - the buffer isn't filled by the terminal until you hit _enter_ because it does its own buffering – Yefim Dinitz Oct 16 '12 at 20:32
1 Answers
2
You can use the standard setvbuf
function to disable buffering (see example below). Note that this will cause buffering to be disabled from the point of view of your program, but not disable buffering in the terminal (which might also be what you want). Example code:
#include <stdio.h>
int main()
{
char c;
setvbuf(stdin, 0, _IONBF, 0);
c = getc(stdin);
printf("read %c\n", c);
return 0;
}
Running it like this will still read input from the terminal line-wise but only consumes the first character entered:
$ ./buf
ab
read a
$ b
Removing the setvbuf
line will cause the whole line of input to be consumed by your program.
There is no portable way to disable the line-buffering of the terminal if using the C standard library only, since it doesn't know about terminals.
EDIT:
One POSIX-portable way of doing what you want is to use the termios functions:
#include <stdio.h>
#include <unistd.h> /* for STDIN_FILENO */
#include <termios.h>
int main()
{
char c;
struct termios old, t;
tcgetattr(STDIN_FILENO, &old);
t = old;
cfmakeraw(&t);
tcsetattr(STDIN_FILENO, TCSANOW, &t);
c = getc(stdin);
tcsetattr(STDIN_FILENO, TCSANOW, &old);
printf("\rread %c\n", c);
return 0;
}

Yefim Dinitz
- 414
- 3
- 9
-
Nah, unfortunately it doesn't satisfy me. I still have to hit _enter_ key (send LF character) to make go further in program. It's not possible? Sad for me. Then I wonder if there is any way (using these compiling settings) to wrote kind of a game (like snake) where program immediately responds to hitting keys... – Sushi271 Oct 16 '12 at 20:25
-
i didn't think it would ;) But using pure C it's simply not possible. You will need to use some OS-specific function to put the terminal in raw mode (see `man termios` for POSIX), or better, a library that does this for you, such as [ncurses](http://www.gnu.org/software/ncurses/) – Yefim Dinitz Oct 16 '12 at 20:30
-
OK, I already did much more in this direction; I have found whole specification of termios struct - even in my language :) - and some flags I have to turn off (ECHO & ICANON). And thanks for "EDIT" as well. Just tell me please one more, slightly different, but little thing (though I think it's easy one): how do I get to know, if some characters are waiting in input buffer (or how much of them)? – Sushi271 Oct 16 '12 at 23:50
-
PS: Y'know, like kbhit() - which also doesn't work in -ansi -pedantic. – Sushi271 Oct 16 '12 at 23:58
-
Sorry, I don't know of any way to do this in POSIX. Also, it's not "easy" for sure, since this concerns actually watching the keyboard now as opposed to turning off stuff in the terminal. BTW, If your goal is to use plain ANSI C, even the termios solution is not valid, since it's POSIX. In ANSI C there is absolutely no way to do what you want, as @Mehrdad rightly pointed out. – Yefim Dinitz Oct 17 '12 at 15:09
-
for more on this topic, you might want to take a look at [the C faq](http://c-faq.com/osdep/cbreak.html) – Yefim Dinitz Oct 17 '12 at 15:16
-
hmmm... And ncurses library (which also isn't plain ANSI, I'm sure) supports some kbhit-like function? – Sushi271 Oct 18 '12 at 15:17
-
not directly, but you can call `timeout(0)` to check for input without blocking in ncurses. – Yefim Dinitz Oct 21 '12 at 08:54