How to get keyboard input without typing enter
I'm just getting back into programming, and this is my first introduction to LINUX. I was wondering if anyone had a basic C program on how to read input from the keyboard one character at a time (without having to press enter)... Thanks!!
On Wednesday 18 February 2004 07:51, Ryan Walsh wrote:
I'm just getting back into programming, and this is my first introduction to LINUX. I was wondering if anyone had a basic C program on how to read input from the keyboard one character at a time (without having to press enter)...
This doesn't work so easily with standard C. The C library only defines getc()
and fgetc() which both read a single character, but it is intentionally
undefined after what user action this occurs.
Since C came into existence along with Unix systems, this makes a lot of
sense: Back in the old days of Unix (the early 1970s) users had terminals.
They didn'd sit in front of the system console (computers where huge and
noisy back then).
This is why even nowadays you need to switch the user's tty (teletypes were
the first terminals in the mid-60s) to a "raw" mode to prevent the user's
input from being buffered until he hits the "return" key - even if that tty
he is working on is really a Linux console or a xterm window.
You need to fiddle with ioctl() to do that, and since there were so many
different types of terminals back then a "terminal data base" (terminfo) came
into existence that helps you to query a specific terminal's capabilities, to
change its settings and to set the correct escape sequences to do even the
most basic things (like, position the cursor). And since this is so much
hassle a library was written around all that that does the dirty parts -
curses, or, today's "new" and improved version, ncurses.
So if you really, really still want to get single characters, read the
documentation about terminal modes, terminfo, and ncurses. If it isn't really
that important, you might as well accept the fact that users have to hit
"return" - or simply change a message from "hit any key" to "hit return" to
make your program continue. ;-)
I know that C compilers on that "other" platform (whose name I will not utter
here...) usually extend that plain C standard to something like cgetc() or
getch() to work around that, but this is no longer standard C.
Isn't it great to have that much heritage to look back upon? ;-)
CU
--
Stefan Hundhammer
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On Tue, 17 Feb 2004 20:51:53 -1000
"Ryan Walsh"
I'm just getting back into programming, and this is my first introduction to LINUX. I was wondering if anyone had a basic C program on how to read input from the keyboard one character at a time (without having to press enter)... This is not part of standard C, but here is a program that I've had hanging around. The Unix/C FAQ also includes something similar. I've been using this for a while. Essentially, you set the terminal to raw mode, (stdin is file descriptor 0). You should use the basic I/O (eg. read(2) not the stdio routines like getc(3)). #include
#include #include #include #include static struct termio save_term; void SetRaw(int fd) { struct termio s;
/*
* Get terminal modes.
*/
(void)ioctl(fd, TCGETA, &s);
/*
* Save modes and set certain variables dependent on modes.
*/
save_term = s;
/*
* Set the modes to the way we want them.
*/
s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
s.c_oflag |= (OPOST|ONLCR|TAB3);
s.c_oflag &= ~(OCRNL|ONOCR|ONLRET);
s.c_cc[VMIN] = 1;
s.c_cc[VTIME] = 0;
(void)ioctl(fd, TCSETAW, &s);
}
static void
TermRestore(int fd)
{
/*
* Restore saved modes.
*/
s = save_term;
(void)ioctl(fd, TCSETAW, &s);
}
int main(int argc, char **argv)
{
int fd, n;
char buf;
fd = 0;
/Set Term to raw mode */
SetRaw(fd);
printf("Enter a digit, q or x to quit\n");
while(1) {
n = read(fd, &buf, 1);
if (n == 1) {
switch(buf) {
case 'q':
case 'Q':
case 'x':
case 'X':
printf("done\n");
TermRestore(fd);
return 0;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
printf(" %c ", buf);
fflush(stdout);
}
} else if (n == 0) {
printf("no input\n");
TermRestore(fd);
return 0;
} else {
TermRestore(fd);
perror("read\n");
return -1;
}
}
}
- --
Jerry Feldman
It might be a good idea to take a quick look at the
Serial-Programming-HOWTO.
Depending on your distribution this is most likely in...
/usr/share/doc/howto/en/html/Serial-Programming-HOWTO/index.html
Chapter 2 gives a good introduction (taught me a lot anyway) to the simplest
ways of waiting for input from a tty.
Even though it sounds like you're not using a serial line, I think a lot of
the principles will carry across and it's very concise.
----- Original Message -----
From: "Jerry Feldman"
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On Tue, 17 Feb 2004 20:51:53 -1000 "Ryan Walsh"
wrote: I'm just getting back into programming, and this is my first introduction to LINUX. I was wondering if anyone had a basic C program on how to read input from the keyboard one character at a time (without having to press enter)... This is not part of standard C, but here is a program that I've had hanging around. The Unix/C FAQ also includes something similar. I've been using this for a while. Essentially, you set the terminal to raw mode, (stdin is file descriptor 0). You should use the basic I/O (eg. read(2) not the stdio routines like getc(3)). #include
#include #include #include #include static struct termio save_term; void SetRaw(int fd) { struct termio s; /* * Get terminal modes. */ (void)ioctl(fd, TCGETA, &s);
/* * Save modes and set certain variables dependent on modes. */ save_term = s;
/* * Set the modes to the way we want them. */ s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); s.c_oflag |= (OPOST|ONLCR|TAB3); s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); s.c_cc[VMIN] = 1; s.c_cc[VTIME] = 0; (void)ioctl(fd, TCSETAW, &s); } static void TermRestore(int fd) { /* * Restore saved modes. */ s = save_term; (void)ioctl(fd, TCSETAW, &s); } int main(int argc, char **argv) { int fd, n; char buf; fd = 0; /Set Term to raw mode */ SetRaw(fd); printf("Enter a digit, q or x to quit\n"); while(1) { n = read(fd, &buf, 1); if (n == 1) { switch(buf) { case 'q': case 'Q': case 'x': case 'X': printf("done\n"); TermRestore(fd); return 0; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': printf(" %c ", buf); fflush(stdout); } } else if (n == 0) { printf("no input\n"); TermRestore(fd); return 0; } else { TermRestore(fd); perror("read\n"); return -1; } } }
- -- Jerry Feldman
Boston Linux and Unix user group http://www.blu.org PGP key id:C5061EA9 PGP Key fingerprint:053C 73EC 3AC1 5C44 3E14 9245 FB00 3ED5 C506 1EA9 -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.2 (GNU/Linux) iD8DBQFAM2xs+wA+1cUGHqkRAtc5AKCIm5+EYQaHJ0yKhm6p+PsUDPOAsACeMtU3 DM8CHhdsUH4oDxff6q1wivg= =10Rr -----END PGP SIGNATURE-----
-- To unsubscribe, email: suse-programming-e-unsubscribe@suse.com For additional commands, email: suse-programming-e-help@suse.com Archives can be found at: http://lists.suse.com/archive/suse-programming-e
It might be a good idea to take a quick look at the Serial-Programming-HOWTO.
Depending on your distribution this is most likely in...
/usr/share/doc/howto/en/html/Serial-Programming-HOWTO/index.html
Chapter 2 gives a good introduction (taught me a lot anyway) to the simplest ways of waiting for input from a tty.
Even though it sounds like you're not using a serial line, I think a lot of the principles will carry across and it's very concise. That is an excellent document, but it goes quite e bit beyond what the original poster wanted, and that is to get a single character from the keyboard (eg. stdin, essentially similar to the Windows conio call (I
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On Wed, 18 Feb 2004 16:39:39 -0000
"Carl Peto"
participants (4)
-
Carl Peto
-
Jerry Feldman
-
Ryan Walsh
-
Stefan Hundhammer