views:

96

answers:

4

I've got a C/C++ program that runs in a console window, and prompts the user to press any key to continue, or 'q' to quit. It currently uses _kbhit() to detect if a key has been pressed, and then uses _getch() to determine what character it was.

Now I want to be able to automate this program (from a C# app using a Process with RedirectStandardInput and CreateNoWindow set). Obviously I can no longer rely on _kbhit() as it uses ReadConsoleInput(), which fails when launched using my C# app. In my C# app I use process.StandardInput.Write("A") to push something onto the stream in an attempt to get my console app to continue.

In the console app I have used SetConsoleMode() to clear the ENABLE_LINE_INPUT flag so that I can use getchar() to return as soon as a character is pressed, and this works reasonably well (when I press a character key in the console window as well as when the call is made from the c# app). However, it has flaws in that it now only accepts characters keys (i.e. no F, Alt, Shift keys etc.) which isn't too big a problem, but moreso I seem to have to press return twice (and this is a key that lots of people will likely choose to press in the 'any key' situation).

Does anyone know how I can make the console app respond to a key (any a bonus, charcters and return only is acceptable) pressed ONCE, whilst still responding to a single character pushed onto the stream from my C# app?

Something I did notice, calling system("PAUSE") gives the exact behaviour I want, other than knowing what key was pressed so that I can quit on 'q'. I don't know how PAUSE does it though, and it doesn't let me use my custom message either :(.

I'm sure there's a really obvious solution, but it has been driving me mad. Any thoughts are much appreciated!

+1  A: 

There are two issues with the resolutions:

  1. Neither the C or C++ languages have portable functions for waiting for a keyboard key to be hit. It's an operating system (platform) issue.*
  2. C and C++ have different methods for resolving I/O. Choose your language, C or C++.

In my C++ console applications, I ask the user to "Press Enter to Continue" and use the ignore method of cin:

void Pause(void)
{
    std::cout << "Press ENTER to continue.\n";
    std::cout.flush(); // Insurance, make sure the text is displayed.
    std::cin.ignore(100000, '\n');  // Ignore characters until an ENTER (newline) is received.
    return;
}

I suggest you create a single file with the Pause function. You can write different versions for different platforms and let the build system select the correct file.

  • Not all platforms that run C or C++ are required to have keyboards. Many embedded systems don't have keyboards. Also, many windowing systems receive messages, events or signals when a key is pressed. Again, something different and not standard.
Thomas Matthews
A portable function for waiting for a keyboard key to be hit does exist -- I have posted it above.
BSchlinker
Sorry, it's not portable across all platforms, especially those without keyboards and non-console applications (such as QT, Windows, etc.). The link is about flushing the input stream. The `kbhit` function mentioned by the OP returns the value of the keyboard press without echoing to the console and bypassing `std::cin`.
Thomas Matthews
My understanding of the OP is that he/she wants *unbuffered* input from the standard input (keyboard). This requires platform specific functions as the C and C++ I/O functions are buffered. Try a small program and see.
Thomas Matthews
I should have said in my post, portability, whilst something I usually strive for, is something I am willing to forego to solve this issue. It is strictly a VC++ running in MS-DOS question :)
Byker Dave
+1  A: 

Here is a very good implementation for C++. Be sure to read over the entire tutorial, as I it may initially appear that it doesn't help you.

http://www.daniweb.com/forums/thread90228.html

BSchlinker
The web page you linked to is about flushing the input stream, not retrieving single keyboard presses. The standard implementation of `std::cin` stores characters until a newline than transfers them to your program. Also, this does not transfer to Windowing applications nor embedded platforms.
Thomas Matthews
@Thomas Please reread the site I posted. Look for the "pause" command, which looks for a single keyboard press (essentially a "Press any Key" routine as the author has requested). The discussion regarding flushing the input stream is important in this case, as existing items in the input stream may result the pause function not working.
BSchlinker
A: 

Use cin.get(). This returns the appropriate key.

DeadMG
In general, this function returns the next available character in the input buffer, which is different than unbuffered input. The `kbhit` function mentioned by the OP returns the keyboard key that was pressed, without any buffering. (I used it in my teenage years.)
Thomas Matthews
Thank you for your reply, but as Thomas Matthews explains, I want it to respond to keyboard presses as they happen, rather than the user having to type and press return. I can get this to happen with cin.get() by using SetConsoleMode() to clear the ENABLE_LINE_INPUT, but it doesn't handle pressing the return key in the manner I would like (needs a double press).
Byker Dave
A: 

Thank you for all your responses, I've learned a lot about handling input!

However, I couldn't get anything to work exactly how I wanted, so I had to abandon the unified approach and put in a check to see if it was running in a window. If it is, I stick with _kbhit(), and if not I use PeekNamedPipe(), which gives me the number of characters sent from my C# app without transfering them into the stdin buffer. There's still a few issues that I have to work out to do with clearing any data that I don't want from the pipe, but it's solved my initial problem.

Thanks again for all the suggestions, they will undoubtably come in handy next time I have an input nightmare :)

Byker Dave