Is it even possible to write a C program that waits for the user input (like cin
in C++) and when a user strikes just one key (no enter), let's say, "a" character on the keyboard the terminal would display "b" (and still wait for the enter)? If so - how can I achieve this?

- 1,807
- 2
- 18
- 30
-
2This is very OS dependent, what OS are you using? also, do you need to store the real input or it is enough to show a `b` for ech key pressed in the console? – David Ranieri Feb 09 '21 at 13:11
-
I'm on Linux; hmm no, I do not think I need to store the real input. It would be nice but it is not required at all. – maciek Feb 09 '21 at 13:12
-
You can get an idea from: https://stackoverflow.com/questions/1786532/c-command-line-password-input/1786628 – Navand Feb 09 '21 at 13:15
-
https://stackoverflow.com/questions/421860/capture-characters-from-standard-input-without-waiting-for-enter-to-be-pressed https://stackoverflow.com/questions/7469139/what-is-the-equivalent-to-getch-getche-in-linux – KamilCuk Feb 09 '21 at 13:15
-
1You need to stop thinking of `cin` as being `the keyboard` – William Pursell Feb 09 '21 at 13:15
-
Please check if this is a duplicate of https://stackoverflow.com/questions/18801483/press-any-key-to-continue-function-in-c/18801616 – sidcoder Feb 09 '21 at 13:15
4 Answers
It is possible, but it's not what "standard" C deals with. You need additional library to achieve this.
You need to realize that standard C (or C++) functions are not meant to work with "keys", or "screen", or "terminal". The only thing they can perform is so-called "standard input and output", which is limited to writing characters somewhere, and reading characters from somewhere. Source and target of characters are not strictly defined and depend on what's attached to the IO streams.
When you think about keys, screens, and terminals, you think about more specific things. You are not interested just with sending and receiving characters between some unspecified places. You want them to come exactly from keys, and end up on the screen. For this, you need a library which would know how to work with keys and screen. One of such libraries is, for example, ncurses
, but there are probably other alternatives.
There are some potential issues related to use of additional libraries: availability, portability, maintainability, etc. You need to account for these factors when you decide what exactly library to use, because final choice depends on your requirements: what platform are you working with? Do you want your code to be portable?

- 1,696
- 12
- 19
For Windows, use the conio.h
library function getch()
, same for Linux but curses.h
instead as an example:
#include <stdio.h>
#include <conio.h> /* or curses if you are on linux*/
int main(void)
{
int c = 0;
c = getch();
if (c == 'a')
{
putchar('b');
getchar(); /* waiting for a newline */
}
return 0;
}
Beware getch()
is not a standard C function.
Edit: As Lundin pointed out in the comments, this is an MS DOS implementation not Windows as I falsely flagged it.

- 1,670
- 2
- 5
- 17
-
3This is a MS DOS solution, not a Windows one. The Windows one would include a WndProc and a window message loop, or alternatively the console API. – Lundin Feb 09 '21 at 13:34
Since you are on Linux and you don't need to store the real input, you can try with termios.h
:
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#define KEY_ENTER 0x000a
#define KEY_ESCAPE 0x001b
static struct termios term, oterm;
static int getch(void);
static int kbhit(void);
static int kbesc(void);
static int kbget(void);
static int getch(void)
{
int c = 0;
tcgetattr(0, &oterm);
memcpy(&term, &oterm, sizeof(term));
term.c_lflag &= ~(ICANON | ECHO);
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
tcsetattr(0, TCSANOW, &term);
c = getchar();
tcsetattr(0, TCSANOW, &oterm);
return c;
}
static int kbhit(void)
{
int c = 0;
tcgetattr(0, &oterm);
memcpy(&term, &oterm, sizeof(term));
term.c_lflag &= ~(ICANON | ECHO);
term.c_cc[VMIN] = 0;
term.c_cc[VTIME] = 1;
tcsetattr(0, TCSANOW, &term);
c = getchar();
tcsetattr(0, TCSANOW, &oterm);
if (c != -1) ungetc(c, stdin);
return ((c != -1) ? 1 : 0);
}
static int kbesc(void)
{
int c;
while (kbhit())
{
c = getch();
}
return c;
}
static int kbget(void)
{
int c;
c = getch();
return (c == KEY_ESCAPE) ? kbesc() : c;
}
int main(void)
{
int c;
while (1)
{
c = kbget();
if (c == KEY_ENTER)
{
break;
}
putchar('b');
}
printf("\n");
return 0;
}
For more complex things consider ncurses

- 39,972
- 7
- 52
- 94
If you're trying to change the input of the user before he presses enter, you'll need to change some configurations of the terminal. The code bellow will read the user input char by char and change any a's to b's. It stops after enter has been pressed.
#include <termios.h>
#include <unistd.h>
int main(void) {
struct termios oldterm, newterm;
tcgetattr(STDIN_FILENO, &oldterm); // save current config
// set new config
newterm = oldterm;
newterm.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL | ICANON);
tcsetattr(STDIN_FILENO, TCSAFLUSH, &newterm);
char ch = 0;
while (read(STDIN_FILENO, &ch, 1) && ch != '\n') {
if (ch == 'a') // show a's as b's
write(STDOUT_FILENO, "b", 1);
else if (ch == 127) // allows deleting chars
write(STDOUT_FILENO, "\b \b", 3);
else // other chars
write(STDOUT_FILENO, &ch, 1);
}
// return to old config
tcsetattr(STDIN_FILENO, TCSANOW, &oldterm);
return 0;
}
You can save the real input by storing the read chars, ch
, in an array.

- 161
- 5