Using Input Function in C on Linux, Without Pressing Enter

How to avoid pressing Enter with getchar() for reading a single character only?

On a linux system, you can modify terminal behaviour using the stty command. By default, the terminal will buffer all information until Enter is pressed, before even sending it to the C program.

A quick, dirty, and not-particularly-portable example to change the behaviour from within the program itself:

#include<stdio.h>
#include<stdlib.h>

int main(void){
int c;
/* use system call to make terminal send all keystrokes directly to stdin */
system ("/bin/stty raw");
while((c=getchar())!= '.') {
/* type a period to break out of the loop, since CTRL-D won't work raw */
putchar(c);
}
/* use system call to set terminal behaviour to more normal behaviour */
system ("/bin/stty cooked");
return 0;
}

Please note that this isn't really optimal, since it just sort of assumes that stty cooked is the behaviour you want when the program exits, rather than checking what the original terminal settings were. Also, since all special processing is skipped in raw mode, many key sequences (such as CTRL-C or CTRL-D) won't actually work as you expect them to without explicitly processing them in the program.

You can man stty for more control over the terminal behaviour, depending exactly on what you want to achieve.

Capture characters from standard input without waiting for enter to be pressed

That's not possible in a portable manner in pure C++, because it depends too much on the terminal used that may be connected with stdin (they are usually line buffered). You can, however use a library for that:

  1. conio available with Windows compilers. Use the _getch() function to give you a character without waiting for the Enter key. I'm not a frequent Windows developer, but I've seen my classmates just include <conio.h> and use it. See conio.h at Wikipedia. It lists getch(), which is declared deprecated in Visual C++.

  2. curses available for Linux. Compatible curses implementations are available for Windows too. It has also a getch() function. (try man getch to view its manpage). See Curses at Wikipedia.

I would recommend you to use curses if you aim for cross platform compatibility. That said, I'm sure there are functions that you can use to switch off line buffering (I believe that's called "raw mode", as opposed to "cooked mode" - look into man stty). Curses would handle that for you in a portable manner, if I'm not mistaken.

getchar() in C is completed without pressing Enter

It's not true that getchar() completes after you press enter. getchar() completes whenever there are characters to read. This difference is significant: see, for example, if you use your program with the standard input redirected to a file:

$ hexdump -C abcd_file 
00000000 61 62 63 64 65 |abcde|
00000005

$ ./in < abcd_file
$

Notice that "abcd_file" is a file that contains "abcde", no newline and your program finishes without requiring a newline anywhere. That's because the file is providing characters all the time and not waiting for a newline.

Common terminals or terminal emulators, on the other hand, have an operation mode that is called the "canonical mode". Canonical mode means that the terminal supports "command line processing facilities" and will not signal an available character until the user presses ENTER. That's where the incorrect "getchar() waits for ENTER" story comes from. You can switch your terminal out of canonical mode and see it retrieving all the characters without the need for pressing enter:

$ stty -icanon; ./in; stty icanon
ggggg$

In this case 5 characters without an enter made the program to finish.

Finally, the reason for getchar() look like it is returning early is because it also returns the ENTER characters. So "a\nb\nc\n" is 6 characters, the first 5 are returned by getchar(), the sixth is deleted from the terminal queue after the program finishes. Typing "abcd\n" also means that getchar() will be immediatelly available for 5 consecutive reads, because there are 5 characters stored in the terminal queue.

http://www.gnu.org/software/libc/manual/html_node/Noncanonical-Input.html#Noncanonical-Input

How to execute the key-corresponding option without an Enter? (C programming)

Linux shares the tty rules of most Unix systems. When a device is seen as a terminal input meaning here something that receive key presses from a human being, the input is by default line oriented. The rationale is that the user is allowed to press a wrong key, cancel it, and finaly press the correct key. In that case, the tty driver handles the fix and only present the final string to the application.

That works fine for line oriented application, but would be foolish for plain screen ones like emacs or vi (yeah, they are from the 70's too...), so the tty driver can be set in raw mode to immediately pass any character to the application (other options exist...). That what the curses library use under the hood to be able to immediately react to any key press.

TL/DR: you must put the tty driver in raw mode to be able to immediately process a character. The details are on the tcflush man page.



Related Topics



Leave a reply



Submit