Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Replacement for _getch()?

93 views
Skip to first unread message

Geoff

unread,
Nov 22, 2013, 11:25:07 AM11/22/13
to
The Microsoft _getch() function gets a character from the console
without echo. It does not require a carriage return. It returns the
character (int) read and does not have an error return. This makes it
very handy for console applications that want to wait for a single
keystroke from the user or for password inputs where echo is
problematic.

Is there a replacement for this non-standard function in C++?

std::cin.ignore() and std::cin.get() fail as direct replacements since
they require the enter key and not just any key be pressed.

Solutions involving ncurses or unistd.h are unsatisfactory for the
same reason conio.h is unsatisfactory.

Öö Tiib

unread,
Nov 22, 2013, 11:50:44 AM11/22/13
to
On Friday, 22 November 2013 18:25:07 UTC+2, Geoff wrote:
> The Microsoft _getch() function gets a character from the console
> without echo. It does not require a carriage return. It returns the
> character (int) read and does not have an error return. This makes it
> very handy for console applications that want to wait for a single
> keystroke from the user or for password inputs where echo is
> problematic.
>
> Is there a replacement for this non-standard function in C++?

No.

> std::cin.ignore() and std::cin.get() fail as direct replacements since
> they require the enter key and not just any key be pressed.
>
> Solutions involving ncurses or unistd.h are unsatisfactory for the
> same reason conio.h is unsatisfactory.

Why? When you do not have something then you write
the function you need on platform that lacks it using what it
has. It is often just a couple of lines of code and internet is
probably full of examples.
For example there is <termios.h> on Linux:

// written in common subset of C and C++:
#include <stdio.h>
#include <termios.h>
static struct termios old, new;

char _getch(void)
{
tcgetattr(0, &old); /* grab old terminal i/o settings */
new = old; /* make new settings same as old settings */
new.c_lflag &= ~ICANON; /* disable buffered i/o */
new.c_lflag &= ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
char ch;
ch = getchar();
return ch;
tcsetattr(0, TCSANOW, &old); /* Restore old terminal i/o settings */
}

Wrote that plus header and you can use your '_getch()'-using code without
changes on Linux.

Öö Tiib

unread,
Nov 22, 2013, 11:53:40 AM11/22/13
to
On Friday, 22 November 2013 18:50:44 UTC+2, Öö Tiib wrote:

Somehow I managed to paste two lines in nonsenical order:

> return ch;
> tcsetattr(0, TCSANOW, &old); /* Restore old terminal i/o settings */

Swap them.

Geoff

unread,
Nov 22, 2013, 12:46:27 PM11/22/13
to
On Fri, 22 Nov 2013 08:50:44 -0800 (PST), �� Tiib <oot...@hot.ee>
wrote:

>On Friday, 22 November 2013 18:25:07 UTC+2, Geoff wrote:
>> The Microsoft _getch() function gets a character from the console
>> without echo. It does not require a carriage return. It returns the
>> character (int) read and does not have an error return. This makes it
>> very handy for console applications that want to wait for a single
>> keystroke from the user or for password inputs where echo is
>> problematic.
>>
>> Is there a replacement for this non-standard function in C++?
>
>No.

That's unfortunate.

>
>> std::cin.ignore() and std::cin.get() fail as direct replacements since
>> they require the enter key and not just any key be pressed.
>>
>> Solutions involving ncurses or unistd.h are unsatisfactory for the
>> same reason conio.h is unsatisfactory.
>
>Why?

Why are they unsatisfactory? Because they are equally non-standard C++
and non-portable. (Yes, I realize console I/O is intimately connected
to the implementation, which is why _getch exists. It's an ancient
MS-DOS'ism that stems from Borland and Lattice C and is an artifact of
Microsoft backward compatibility.)

>When you do not have something then you write
>the function you need on platform that lacks it using what it
>has.

I was trying to avoid reinventing the wheel.

>It is often just a couple of lines of code and internet is
>probably full of examples.
>For example there is <termios.h> on Linux:
>
>// written in common subset of C and C++:
>#include <stdio.h>
>#include <termios.h>
>static struct termios old, new;
>
>char _getch(void)
>{
> tcgetattr(0, &old); /* grab old terminal i/o settings */
> new = old; /* make new settings same as old settings */
> new.c_lflag &= ~ICANON; /* disable buffered i/o */
> new.c_lflag &= ~ECHO; /* set echo mode */
> tcsetattr(0, TCSANOW, &new); /* use these new terminal i/o settings now */
> char ch;
> ch = getchar();
> return ch;
> tcsetattr(0, TCSANOW, &old); /* Restore old terminal i/o settings */
>}
>
>Wrote that plus header and you can use your '_getch()'-using code without
>changes on Linux.

I was aware of this code and was considering using it, thanks for
validating my suppositions about this. The above example is flawed,
however. The functions return int, not char.

int _getch(void)
{
struct termios oldattr, newattr;
int ch;

tcgetattr( STDIN_FILENO, &oldattr );
newattr = oldattr;
newattr.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
return ch;
}


My goal is less about OS portability and more about standardizing the
code but this will have to do, I suppose.

Richard Damon

unread,
Nov 22, 2013, 11:50:02 PM11/22/13
to
On 11/22/13, 11:25 AM, Geoff wrote:
> The Microsoft _getch() function gets a character from the console
> without echo. It does not require a carriage return. It returns the
> character (int) read and does not have an error return. This makes it
> very handy for console applications that want to wait for a single
> keystroke from the user or for password inputs where echo is
> problematic.
>
> Is there a replacement for this non-standard function in C++?
>
_getch()

> std::cin.ignore() and std::cin.get() fail as direct replacements since
> they require the enter key and not just any key be pressed.
>
> Solutions involving ncurses or unistd.h are unsatisfactory for the
> same reason conio.h is unsatisfactory.
>

It is a non-standard function in C, and isn't something provided by the
C++ either. It should work in C++ to, so it seems to be your best choice.

The other alternative would be to make the same system call that
_getch() uses internally to do the action.

Geoff

unread,
Nov 23, 2013, 1:56:47 PM11/23/13
to
On Fri, 22 Nov 2013 23:50:02 -0500, Richard Damon
<Ric...@Damon-Family.org> wrote:

>On 11/22/13, 11:25 AM, Geoff wrote:
>> The Microsoft _getch() function gets a character from the console
>> without echo. It does not require a carriage return. It returns the
>> character (int) read and does not have an error return. This makes it
>> very handy for console applications that want to wait for a single
>> keystroke from the user or for password inputs where echo is
>> problematic.
>>
>> Is there a replacement for this non-standard function in C++?
>>
>_getch()

Obviously. But that's not a "replacement", is it?

>
>> std::cin.ignore() and std::cin.get() fail as direct replacements since
>> they require the enter key and not just any key be pressed.
>>
>> Solutions involving ncurses or unistd.h are unsatisfactory for the
>> same reason conio.h is unsatisfactory.
>>
>
>It is a non-standard function in C, and isn't something provided by the
>C++ either. It should work in C++ to, so it seems to be your best choice.
>

Yes, the leading underscore designates it as a compiler extension per
the standard requirements. Indeed, it does work for a Windows console
application in Microsoft C++ and it appears to be the only choice for
that functionality. The only "standard" alternative is cin.ignore()
which buffers and echoes characters until the return key is pressed.

>The other alternative would be to make the same system call that
>_getch() uses internally to do the action.

Reading Microsoft's source in getch.c, _getch obtains the console lock
and calls _getch_nolock() which manipulates the console mode via the
GetConsoleMode/SetConsoleMode API functions and then goes into an
infinite loop waiting on ReadConsoleInput(), then it resets the
console mode and returns the character received. So much for any
standards compliance.

Nobody

unread,
Nov 24, 2013, 4:51:08 PM11/24/13
to
On Fri, 22 Nov 2013 09:46:27 -0800, Geoff wrote:

> I was aware of this code and was considering using it, thanks for
> validating my suppositions about this. The above example is flawed,
> however. The functions return int, not char.

Also, it doesn't install any signal handlers so the terminal state won't
be restored if the process is suspended or terminated while the function
is waiting for a key press. And modifying the terminal settings affects
all processes which are connected to the terminal.

One of the main reasons why C++ doesn't standardise getch() is because
it's a DOS-ism, i.e. something which only makes sense on a "PC", and the
people responsible for standardising C++ don't appear to share the
misconception that "computer" and "PC" are synonyms.

Alf P. Steinbach

unread,
Nov 24, 2013, 5:28:18 PM11/24/13
to
On 24.11.2013 22:51, Nobody wrote:
>
> One of the main reasons why C++ doesn't standardise getch() is because
> it's a DOS-ism, i.e. something which only makes sense on a "PC",

With block mode terminals I guess it won't make much sense. But then
e.g. iostreams don't make much sense for embedded programming either.
And I've used similar functions in many programming languages on a
variety of systems, including *nix, with a variety of terminals, since
the early 1980s, so it's not a function that's specific to PCs.

Just clearing up the technical.

But I guess that this noise is meant as a jab in the direction of
someone, trying to convey the misleading impression that that someone
(Tib? the OP?) does not have a properly wide view of computing:

> and the
> people responsible for standardising C++ don't appear to share the
> misconception that "computer" and "PC" are synonyms.


- Alf

Geoff

unread,
Nov 24, 2013, 10:12:24 PM11/24/13
to
On Sun, 24 Nov 2013 21:51:08 +0000, Nobody <nob...@nowhere.com> wrote:

>On Fri, 22 Nov 2013 09:46:27 -0800, Geoff wrote:
>
>> I was aware of this code and was considering using it, thanks for
>> validating my suppositions about this. The above example is flawed,
>> however. The functions return int, not char.
>
>Also, it doesn't install any signal handlers so the terminal state won't
>be restored if the process is suspended or terminated while the function
>is waiting for a key press. And modifying the terminal settings affects
>all processes which are connected to the terminal.

This would seem to be an issue only with *nix then, since modifying a
Windows console only affects the instance of that application's
console, not all consoles. I can't vouch for what may happen if a
process is terminated but I believe Windows will clean it up. I
suppose that particular snippet assumes (and doesn't document that
assumption) that an instance handler would be defined.

That particular code sample goes back years to some pretty flippant
and flawed advice on several web forums on the topic of _getch
replacement so I'm not surprised it has issues.

>
>One of the main reasons why C++ doesn't standardise getch() is because
>it's a DOS-ism, i.e. something which only makes sense on a "PC", and the
>people responsible for standardising C++ don't appear to share the
>misconception that "computer" and "PC" are synonyms.

While it may be a DOS-ism the functionality of receiving a character
or string of characters without echoing them is universal, even when
there isn't a keyboard on the "computer".

My primary goal wasn't portability so much as "standardizing" a
particularly old program dating back to 1988 or so. Microsoft, in
their dedication to legacy functionality, conveniently provides
identical functionality in VB and C# as Console.ReadKey(true). I was
hoping for something similar in standard C/C++.

Nobody

unread,
Nov 29, 2013, 2:39:29 PM11/29/13
to
On Sun, 24 Nov 2013 23:28:18 +0100, Alf P. Steinbach wrote:

>> One of the main reasons why C++ doesn't standardise getch() is because
>> it's a DOS-ism, i.e. something which only makes sense on a "PC",
>
> With block mode terminals I guess it won't make much sense. But then e.g.
> iostreams don't make much sense for embedded programming either. And I've
> used similar functions in many programming languages on a variety of
> systems, including *nix, with a variety of terminals, since the early
> 1980s, so it's not a function that's specific to PCs.

The functionality may not be specific to PCs, but the getch() API is. On
Unix (or other systems whose model of interactive input is based upon
dedicated terminals connected to serial ports), "read character without
echo" cannot be simplified to a single getch() function without being
oversimplified.

Configuring the terminal is a specific operation, as are reading
characters, restoring the terminal to its original state, and ensuring
that the terminal is restored upon suspend and reconfigured upon resume.

And iostreams are perfectly useful for embedded programming. "iostream"
doesn't automatically mean "fstream" (and plenty of embedded platforms
have filesystems).

Alf P. Steinbach

unread,
Nov 29, 2013, 2:53:32 PM11/29/13
to
On 29.11.2013 20:39, Nobody wrote:
> On Sun, 24 Nov 2013 23:28:18 +0100, Alf P. Steinbach wrote:
>
>>> One of the main reasons why C++ doesn't standardise getch() is because
>>> it's a DOS-ism, i.e. something which only makes sense on a "PC",
>>
>> With block mode terminals I guess it won't make much sense. But then e.g.
>> iostreams don't make much sense for embedded programming either. And I've
>> used similar functions in many programming languages on a variety of
>> systems, including *nix, with a variety of terminals, since the early
>> 1980s, so it's not a function that's specific to PCs.
>
> The functionality may not be specific to PCs, but the getch() API is. On
> Unix (or other systems whose model of interactive input is based upon
> dedicated terminals connected to serial ports), "read character without
> echo" cannot be simplified to a single getch() function without being
> oversimplified.

So?

Why would anyone would want just a single function?


> Configuring the terminal is a specific operation, as are reading
> characters, restoring the terminal to its original state, and ensuring
> that the terminal is restored upon suspend and reconfigured upon resume.

That's what C++ constructors and destructors help to automate:
initialization and cleanup. Yay! :-)

Anyway, I suggest you try the "curses" library (in one of its
incarnations), even if it's C language; IIRC it does much of this for you.

http://linux.die.net/man/3/getch


> And iostreams are perfectly useful for embedded programming. "iostream"
> doesn't automatically mean "fstream" (and plenty of embedded platforms
> have filesystems).

So in your opinion I should have written "fstream", not "iostreams", yes?


Cheers, & have a nice weekend!,

- Alf

0 new messages