getch() alternative - NOT getchar()

Hey hey C++ forum,

I'm finally back! Exams are done and I finally have time to code again :D
So I'm making this little addressbook app in the console. I need the user to be able to navigate without having to press enter each time.
I.E. when the user presses "2", it should immediately stored in a variable, without first having to press enter. I know getch() can do this, but I've heard that's a bad habit...

Are there any alternatives?

Thank you!

Xander
You need to disable line buffering:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
	/*
	 * Disable character echoing and line buffering
	 */
#if defined(WINDOWS)
	HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
	DWORD mode;

	if (!GetConsoleMode(hstdin, &mode))
		return -1;

	if (hstdin == INVALID_HANDLE_VALUE || !(SetConsoleMode(hstdin, 0)))
		return -1; /* Failed to disable buffering */
#elif defined(POSIX)
	struct termios tty_attr;

	if (tcgetattr(STDIN_FILENO, &tty_attr) < 0)
		return -1;

	const tcflag_t c_lflag = tty_attr.c_lflag; /* Allows us to restore this later */
	tty_attr.c_lflag &= ~ICANON;
	tty_attr.c_lflag &= ~ECHO;

	if (tcsetattr(STDIN_FILENO, 0, &tty_attr) < 0)
		return -1;
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
	/*
	 * Re-enable character echoing and line buffering
	 */
#if defined(WINDOWS)
	if (!SetConsoleMode(hstdin, mode))
		return -1;
#elif defined(POSIX)
	tty_attr.c_lflag = c_lflag;

	if (tcsetattr(STDIN_FILENO, 0, &tty_attr) < 0)
		return -1;
#endif 


This was taken from a getpassword() function I wrote. I can't remember if I've tested it on Windows, but it definitely works on Linux.
Wow, I don't understanD one word of what you're doing there xD
But thanks for helping!
Unless someone comes up with an easier solution I'll use that one :)

Xander
please visit this site:
http://codewall.blogspot.com/2010/12/automated-teller-machine-atm-in-c.html
this atm program used getch() function. A simple but really useful.
Last edited on
@thecodewall,
Firstly, OP specifically stated that he is looking for an alternative to getch(). Secondly, you should _never_ use conio.h

@xander333,
It just does what the comments say it does, but I used the preprocessor so hat it would work both on Windows and Linux.

Here is the same code but as functions you can call:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#if defined(WINDOWS)
static DWORD stdin_mode;
#elif defined(POSIX)
static tcflag_t c_lflag = tty_attr.c_lflag;
#endif

int save_tty_attributes()
{
#if defined(WINDOWS)
	HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);

	if (!GetConsoleMode(hstdin, &mode))
		return -1;

	if (hstdin == INVALID_HANDLE_VALUE || !(SetConsoleMode(hstdin, 0)))
		return -1; /* Failed to disable buffering */
#elif defined(POSIX)
	struct termios tty_attr;

	if (tcgetattr(STDIN_FILENO, &tty_attr) < 0)
		return -1;

	tty_attr.c_lflag &= ~ICANON;
	tty_attr.c_lflag &= ~ECHO;

	if (tcsetattr(STDIN_FILENO, 0, &tty_attr) < 0)
		return -1;
#endif 
}

int restore_tty_attributes()
{
#if defined(WINDOWS)
	if (!SetConsoleMode(hstdin, mode))
		return -1;
#elif defined(POSIX)
	tty_attr.c_lflag = c_lflag;

	if (tcsetattr(STDIN_FILENO, 0, &tty_attr) < 0)
		return -1;
#endif 
}

int sgetchar()
{
	int c = 0;
	save_tty_attributes();
	c = getchar();
	restore_tty_attributes();
	return c;
}


Then you would just call sgetchar() to get a character with no echo.
Ok thanks a lot!
Topic archived. No new replies allowed.