how to read a single keystroke in C++

F

Frank Bormann

Hi,

probably a stupid question, but I haven't been able to find anything.

Is there a istream related function that let me read exactly one keystroke
from the keyboard through cin?

What I need it to do is this:
- remove all characters currently in the input buffer
- block until the user presses a key
- return the ascii code of the key that was pressed

This should work also, if the user just hit the enter key.

I'm probably too stupid to get it right, but the usual get/getline()
functions always block until the user hits enter, even if the user enteres
other keys before, but on the other hand, if the user presses enter only,
getline continues to block and does not return the empty line.

Ideally I would like somethink like this:

1. a menu, where the user can press 1, 2 or 3 (and the program reactiving
immediately without the need for the user to press enter afterwards)
2. a "Press any key to continue" function, that waits for exactly one
keystroke, no matter what key it is.

Frank
 
V

Victor Bazarov

Frank said:
probably a stupid question, but I haven't been able to find anything.

Is there a istream related function that let me read exactly one keystroke
from the keyboard through cin? [...]

There is no such thing as 'keyboard' AFA C++ _language_ is concerned.
 
F

Frank Bormann

Victor Bazarov said:
Frank said:
probably a stupid question, but I haven't been able to find anything.

Is there a istream related function that let me read exactly one keystroke
from the keyboard through cin? [...]

There is no such thing as 'keyboard' AFA C++ _language_ is concerned.

Ok, let me ask differently: How can I determine, if there are chars to read
in the cin streambuf without blocking? I've tried to use in_avail() and
readsome(), but they always return 0 on cin, even if there's still input
data present in the buffer.
 
V

Victor Bazarov

Frank said:
Frank said:
probably a stupid question, but I haven't been able to find anything.

Is there a istream related function that let me read exactly one
keystroke
from the keyboard through cin? [...]

There is no such thing as 'keyboard' AFA C++ _language_ is concerned.


Ok, let me ask differently: How can I determine, if there are chars to read
in the cin streambuf without blocking? I've tried to use in_avail() and
readsome(), but they always return 0 on cin, even if there's still input
data present in the buffer.

Let me ask you, then. If 'in_avail' or 'readsome' returns 0, what makes
you think that "there's still input data present"? I mean, if you have
some other way of knowing that there are data in the stream, why don't
you use the same method to read it? Catch my drift?
 
I

Ioannis Vranos

Frank said:
Ok, let me ask differently: How can I determine, if there are chars to read
in the cin streambuf without blocking? I've tried to use in_avail() and
readsome(), but they always return 0 on cin, even if there's still input
data present in the buffer.


I suppose in most PCs, cin accepts input only after you press Enter, so the closest thing
I can suggest is using the old, good, system-dependent extensions, getch() and getche()
(the second echoes the input). It is usually defined in conio.h when it is available.

They are not part of the C++ standard though.
 
F

Frank Bormann

Victor Bazarov said:
Let me ask you, then. If 'in_avail' or 'readsome' returns 0, what makes
you think that "there's still input data present"? I mean, if you have
some other way of knowing that there are data in the stream, why don't
you use the same method to read it? Catch my drift?

There's still input data present, because get() or getline() reads it. My
problem currently is this:

I want some "Press any key to continue" like implementation. Or at least
"Press <return> to continue" which would be less nice but still acceptable.
Now, if I use cin.getline() to try and read such input, the cin.getline()
call never returns, if the user just presses the <return> key (apparently
because it's an empty line and getline discards that). If instead I use
"char c; cin.get(c);" and the user instead of just pressing <return> had
entered some other characters before pressing return, I read only the first
character and the others remain in the buffer. Now, the next time, program
flow comes across this "Press <return> to continue" code, the cin.get(c)
immediately reads the first of the characters that are still in the buffer
from the previous input. I can of course call
cin.ignore(numeric_limits<streamsize>::max()); as described in the C++ FAQ
to get rid of those characters, but if I do that and the buffer was already
empty, it never returns from the cin.ignore() call, no matter what I enter.
So I need to have a non-blocking way of knowing, if there are characters in
the cin buffer, so I can check before calling ignore.

Frank
 
F

Frank Bormann

Ioannis Vranos said:
Frank Bormann wrote:

I suppose in most PCs, cin accepts input only after you press Enter, so the closest thing
I can suggest is using the old, good, system-dependent extensions, getch() and getche()
(the second echoes the input). It is usually defined in conio.h when it is
available.

I was afraid, you were going to say that. I was thinking about that too, I'm
sure, I could easily manage to get what I want, by using the low-level file
descriptor i/o of the glibc, but I was hoping to find a system-independent
solution.

Frank
 
K

Karl Heinz Buchegger

Frank said:
There's still input data present, because get() or getline() reads it. My
problem currently is this:

I want some "Press any key to continue" like implementation. Or at least
"Press <return> to continue" which would be less nice but still acceptable.
Now, if I use cin.getline() to try and read such input, the cin.getline()
call never returns, if the user just presses the <return> key (apparently
because it's an empty line and getline discards that).

Aehm. Then you did something wrong.

#include <string>
#include <iostream>

using namespace std;

int main()
{
string input;

cout << "Press <return> to continue\n";
getline( cin, input );

cout << "Bye\n";
}

waits exactly for the user pressing return.
Ok. The user can enter other things before the return, but
it definitly will return by just pressing the said:
If instead I use
"char c; cin.get(c);" and the user instead of just pressing <return> had
entered some other characters before pressing return, I read only the first
character and the others remain in the buffer. Now, the next time, program
flow comes across this "Press <return> to continue" code, the cin.get(c)
immediately reads the first of the characters that are still in the buffer
from the previous input.

OK. So what is hindering you to do:

char c;
while( cin.get(c) != '\n' )
;

That is: loop until the return key is detected?
You *know* that there has to be a '\n' somewhere.
 
K

Karl Heinz Buchegger

Frank said:
available.

I was afraid, you were going to say that. I was thinking about that too, I'm
sure, I could easily manage to get what I want, by using the low-level file
descriptor i/o of the glibc, but I was hoping to find a system-independent
solution.

No.
As a rule of thumb: C++ knows nothing about any hardware. No keyboard, no mouse,
no monitor, no harddisk, no network, ...

Accessing such things is always platform dependent.
 
S

Sebastian Redl

Frank said:
Hi,

probably a stupid question, but I haven't been able to find anything.

Is there a istream related function that let me read exactly one keystroke
from the keyboard through cin?

Not a stupid question at all, because it's a tricky problem.

First, in_avail has always worked fine for me. I don't know why it wouldn't
work for you, so I can't help you there.

Second, cin calls blocking until enter is hit is not a problem of cin, but
of the OS. There are WinAPI calls (I don't know which exactly) that you can
use to set the console into return-after-each-character mode.

Third, I'm pretty sure - no, actually I *know*, because that very fact
caused me trouble just yesterday - that getline (at least the std::string
version) does not discard empty lines.
 
F

Frank Bormann

Karl Heinz Buchegger said:
Aehm. Then you did something wrong.

Thank you!!! Yes, I was using the istream member function getline, not this
global string function.
This finally works at least for the "Press <return> to continue".

Frank
 
P

Pelle Beckman

Frank Bormann skrev:
Hi,

probably a stupid question, but I haven't been able to find anything.

Is there a istream related function that let me read exactly one keystroke
from the keyboard through cin?

...
Frank

This is an OT-answer for Win32

_#include <stdlib.h>_

_system ("PAUSE");_

gives

"Press any key to continue"

Wasn't that what you were looking for?

-- Pelle
 
S

sam

Ioannis said:
I suppose in most PCs, cin accepts input only after you press Enter, so
the closest thing I can suggest is using the old, good, system-dependent
extensions, getch() and getche() (the second echoes the input). It is
usually defined in conio.h when it is available.
I never use this API in g++ before. Is it similar to curses base IO API?
In curses C API, it can do exactly what the OP is asking for.
Surely, you can "Wrap" curses C API into C++ classes. Perhaps curses has
already had a set of C++ API in the open source community.

Sam.
 
M

Mike Wahler

Frank Bormann said:
available.

I was afraid, you were going to say that. I was thinking about that too,
I'm
sure, I could easily manage to get what I want, by using the low-level
file
descriptor i/o of the glibc, but I was hoping to find a system-independent
solution.

The only way to do (almost) that is to specifically support certain known
platforms/implementations via conditional compilation:

#ifdef THIS_PATFORM
this_platform_get();
#elseif THAT_PLATFORM
that_platform_get();
#else
some_standard_blocking_input_function();
#endif

-Mike
 
M

Mike Wahler

Sebastian Redl said:
Not a stupid question at all, because it's a tricky problem.

First, in_avail has always worked fine for me. I don't know why it
wouldn't
work for you, so I can't help you there.

Second, cin calls blocking until enter is hit is not a problem of cin, but
of the OS. There are WinAPI calls (I don't know which exactly) that you
can
use to set the console into return-after-each-character mode.

Third, I'm pretty sure - no, actually I *know*, because that very fact
caused me trouble just yesterday - that getline (at least the std::string
version) does not discard empty lines.

<OT>
If you're using VC++ 6.0, note that the 'std::getline()' supplied
with it has a bug which causes the behavior you describe, the fix to
which is available at http://www.dinkumware.com/vc_fixes.html
(One or more of the later VC++ 'service packs' from Microsoft might also
address this problem, I didn't check).
</OT>

-Mike
 
Joined
Apr 5, 2009
Messages
1
Reaction score
0
Keystroke in c++

#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>

int kbhit(void)
{
struct termios oldt, newt;
int ch;
int oldf;

tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);

ch = getchar();

tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);

if(ch != EOF)
{
ungetc(ch, stdin);
return 1;
}

return 0;
}

int main(void)
{
while(!kbhit())
puts("Press a key!");
printf("You pressed '%c'!\n", getchar());
return 0;
}


itsme@dreams:~/C$ ./kbhit
Press a key!
Press a key!
Press a key!
Press a key!
.
.
.
Press a key!
Press a key!
Press a key!
Press a key!
Press a key!
You pressed 'r'!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,163
Latest member
Sasha15427
Top