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

Non-blocking getchar()

2,896 views
Skip to first unread message

Olaf Meding

unread,
Feb 28, 2001, 6:39:33 PM2/28/01
to

Is there a non blocking getchar() type function?

I am looking for a function that returns immediately the key (code) pressed
or 0 or -1 if no key has been pressed.


Using VC6 to create Win32, non MFC, console apps for NTW 4.0.

Olaf
TomoTherapy

Please remove "noSpam" to get my email address


Vincent Fatica

unread,
Feb 28, 2001, 7:34:20 PM2/28/01
to
How 'bout

if ( kbhit() ) c = getch(); /* or getche() */

- Vince

Vincent Fatica
vefa...@syr.edu
Syracuse University Mathematics
http://barnyard.syr.edu/~vefatica/

Olaf Meding

unread,
Mar 1, 2001, 9:43:13 AM3/1/01
to
Vince,

> if ( kbhit() ) c = getch();

This will not work in all cases because kbhit() does not tell you how many
characters there are in the input buffer.

Vincent Fatica

unread,
Mar 1, 2001, 10:12:28 AM3/1/01
to
On Thu, 1 Mar 2001 08:43:13 -0600, "Olaf Meding"
<ol...@noSpam.TomoTherapy.com> wrote:

>> if ( kbhit() ) c = getch();
>
>This will not work in all cases because kbhit() does not tell you how many
>characters there are in the input buffer.

Do you **need** to know, in advance, how many characters are waiting?
That's an unusual scenario. If you remove one of many characters from the
input buffer, kbhit() will continue to return true, so put it in a loop:

char szString[MAX_PATH];
unsigned int i = 0;
while ( kbhit() ) szString[i++] = getch();
szString[i] = 0;
printf("%u characters were read. They were: %s\n", i, szString);

- Vince

Olaf Meding

unread,
Mar 1, 2001, 3:03:44 PM3/1/01
to
Vince,

Here is the problem. I would like to do a WaitForMultipleObjects() with one
object being the keyboard. Once the console is signaled I like to get all
keys but never want to get blocked extracting keys.

The test code below does not work because the handle remains signaled after
a key is pressed and attempting the reset the handle results in a invalid
handle error.


// Wake up when the user presses keys on the keyboard.
handle = GetStdHandle( STD_INPUT_HANDLE );

while ( !done ) {
printf( "Waiting for keyboard input \n" );
WaitForSingleObject(
handle, // handle of object to wait for
INFINITE // time-out interval in milliseconds
);

while ( kbhit() ) {
printf( "Getting key ... \n" );
key = _getch();
if ( key == 27 ) done = TRUE;
printf( "%d ", key );
}

ok = ResetEvent( handle );
if ( !ok ) {
printf( "*** Problem resetting event, error: %d \n",
GetLastError() );
return 0;

Vincent Fatica

unread,
Mar 1, 2001, 9:25:47 PM3/1/01
to
How do you plan to know when the user stops entering characters?

- Vince

Vincent Fatica

unread,
Mar 1, 2001, 11:06:21 PM3/1/01
to
On Thu, 1 Mar 2001 14:03:44 -0600, "Olaf Meding"
<ol...@noSpam.TomoTherapy.com> wrote:

>Here is the problem. I would like to do a WaitForMultipleObjects() with one
>object being the keyboard. Once the console is signaled I like to get all
>keys but never want to get blocked extracting keys.

This seems to be what you tried to do (but it's overkill):

char c;
HANDLE hKeyBoard = GetStdHandle(STD_INPUT_HANDLE);
/* Make sure the handle starts unsignalled */
FlushConsoleInputBuffer(hKeyBoard);
while ( TRUE ) {
WaitForSingleObject(hKeyBoard, INFINITE);
if ( (c = getch()) == 27 ) break;
printf("%c", c == '\r' ? '\n' : c); // translate <Enter> //
/* hKeyBoard should now be unsignalled; doesn't matter */
/* since if there's another char there (signalled), it's */
/* because the user put it there. */
}

Perhaps I'm misunderstanding, but, once the handle is signalled, the user
has started entering keystrokes, so just getch() (see below) until he enters
<Esc>. What's the difference if you're blocked waiting for him to press
<Esc> or blocked because you've issued another WaitFSO()? I don't think you
can ResetEvent() on such a handle. If you really want to make sure the input
buffer is really empty before issuing a WaitFSO(), use
FlushConsoleInputBuffer().

char c;
HANDLE hKeyBoard = GetStdHandle(STD_INPUT_HANDLE);

/* Make sure it starts unsignalled */
FlushConsoleInputBuffer(hKeyBoard);

/* Wait until user starts entering keystrokes */
WaitForSingleObject(hKeyBoard, INFINITE);

/* Read keystrokes until he presses <Esc> */
while ( (c = getch()) != 27 ) {
if ( c == '\r' ) c = '\n'; /* translate <Enter> */
printf("%c", c);
}

>The test code below does not work because the handle remains signaled after
>a key is pressed and attempting the reset the handle results in a invalid
>handle error.
>
>
>// Wake up when the user presses keys on the keyboard.
>handle = GetStdHandle( STD_INPUT_HANDLE );
>
>while ( !done ) {
> printf( "Waiting for keyboard input \n" );
> WaitForSingleObject(
> handle, // handle of object to wait for
> INFINITE // time-out interval in milliseconds
> );
>
> while ( kbhit() ) {
> printf( "Getting key ... \n" );
> key = _getch();
> if ( key == 27 ) done = TRUE;
> printf( "%d ", key );
> }
>
> ok = ResetEvent( handle );
> if ( !ok ) {
> printf( "*** Problem resetting event, error: %d \n",
>GetLastError() );
> return 0;
> }
>}
>
>
>Olaf
>TomoTherapy
>
>Please remove "noSpam" to get my email address
>

Vincent Fatica

Olaf Meding

unread,
Mar 2, 2001, 11:28:57 AM3/2/01
to
Vincent,

Thank you very much for suggesting using FlushConsoleInputBuffer().

I now have what I was looking for for a long time. Can wait for multiple
events now, such as my thread ending, while at the same time watching for
keyboard input. Also, the ctrl-c key now works correctly because there is
no outstanding getchar(). And I do not need to do anything special after
the user presses the Esc key, just send a message to my thread and the while
loop already waits for the thread to exit. FYI, below is my final code.


Thanks again for your help.

Olaf
TomoTherapy

Please remove "noSpam" to get my email address

// Include system header files.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows
headers
#include <windows.h>
#include <process.h>


// Include vendor header files.


// Include project header files.
#include "realTimeData.h"


// Define statements.
#undef WHO
#define WHO "testRealTimeData: " // Who caused error log.


// Macros.


// Enumerations and type declarations.


// External variables.


// Global variables.


// Static variables.


// External function declarations.


// Static function declarations.
static BOOL handlerRoutine( DWORD signal );


/*--------------------------------------------------------------------------
--
|
| main()
|
+---------------------------------------------------------------------------
*/

int main ( int argc, char* argv[] )
{
#undef FUN
#define FUN "main: "

int rc = 0;
HANDLE handles[2];
DWORD threadId; // not used but needed by '_beginthreadex()'
DWORD waitStatus;
DWORD exitCode;
BOOL done;
BOOL ok;
int key;


printf( "\n" "Press ? for valid keys, Esc to exit" "\n\n" );

// Add a handler function to catch the ctrl-c keys.
// Note, the user would press ctrl-c to shutdown this applications.
SetConsoleCtrlHandler( (PHANDLER_ROUTINE)handlerRoutine, TRUE );

// Need to wake up when the user presses keys on the keyboard.
// Get a handle to standard input.
handles[0] = GetStdHandle( STD_INPUT_HANDLE );

// Create CORBA thread.
printf( WHO FUN "creating CORBA thread ... \n" );
handles[1] = (HANDLE)_beginthreadex(
NULL, // security descriptor
0, // initial thread stack size, in bytes
initRealTimeData, // pointer to thread function
NULL, // argument list for new thread
0, // creation flags
&threadId // pointer to returned thread identifier
);
if ( handles[1] == 0 )
printf( WHO FUN "failed to create CORBA thread, error: %d \n",
errno );
else
printf( WHO FUN "created CORBA thread \n" );

// Flush all events from the standard input buffer.
FlushConsoleInputBuffer( handles[0] );

done = FALSE;
while ( !done ) {

// Wait for keyboard keys or for CORBA thread to finish.
waitStatus = WaitForMultipleObjects(
2, // number of handles in the object handle
array
handles, // pointer to the object-handle array
FALSE, // wait flag ('TRUE' = all signaled objects)


INFINITE // time-out interval in milliseconds
);

switch( waitStatus ) {
case WAIT_FAILED :
printf( WHO FUN "wait failed, Win32 error: %d",
GetLastError() );
break;

case WAIT_TIMEOUT :
// Ignore.
break;

case WAIT_OBJECT_0 + 0 :
// Detected an event in standard input buffer.

// Interpret keys pressed by user.
while ( kbhit() ) {
file://printf( "key: " );
key = _getch();
file://printf( "%d \n", key );

switch( key ) {
case 0 :
case 0xE0:
// Ignore extended keys.
file://printf( "extended key: " );
key = _getch(); // discard extended key code
file://printf( "%d \n", key );
break;

case 27 :
// User pressed to Esc key.

// Terminate the CORBA server.
termRealTimeData();
break;

case '\r' :
// User wants to seperate status messages with a blank
line.
printf( "\n" );
break;

case '?' :

ntf(
"Valid keys: \n"
" Enter -- seperate status messages \n"
" Esc -- exit \n"
"\n"
);
break;

default :
break;
}
}

// Flush all events from the standard input buffer.
FlushConsoleInputBuffer( handles[0] );
break;

case WAIT_OBJECT_0 + 1 :
// CORBA thread returned.
GetExitCodeThread( handles[1], &exitCode );
printf(
WHO FUN "CORBA thread returned, exit code: %d \n", exitCode );
done = TRUE;
break;

default:
printf(
WHO FUN "received unexpected event, Win32 error: %d",
GetLastError()
);
break;

}
}

// Close the standard input handle.
ok = CloseHandle( handles[0] );
if ( !ok )
printf( WHO FUN "failed to close the standard input handle \n" );

// Close the CORBA thread handle.
ok = CloseHandle( handles[1] );
if ( !ok )
printf( WHO FUN "failed to close the standard input handle \n" );

return rc;

}


/*-----------
-----------------------------------------------------------------
|
| handlerRoutine()
|
| Catch the ctrl-c keys.
|
+---------------------------------------------------------------------------
*/

static BOOL handlerRoutine( DWORD signal )
{
#undef FUN
#define FUN "handlerRoutine: "


switch( signal ) {
case CTRL_C_EVENT:
printf( WHO FUN "Detected a Ctrl-C signal \n");
// Terminate the CORBA server.
termRealTimeData();
return TRUE;
break;

case CTRL_BREAK_EVENT:
printf( "\n" WHO FUN "detected a Ctrl-Break signal \n");
return FALSE;
break;

case CTRL_CLOSE_EVENT:
printf( "\n" WHO FUN "detected a Close Console signal \n");
return FALSE;
break;

case CTRL_LOGOFF_EVENT:
printf( "\n" WHO FUN "detected a User Logoff signal \n");
return FALSE;
break;

case CTRL_SHUTDOWN_EVENT:
printf( "\n" WHO FUN "detected a System Shutdown signal \n");
return FALSE;
break;

default:
printf("\n" WHO FUN "detected an unknown signal \n");
return FALSE;
break;
}

}


0 new messages