Unbuffered input

I realize I'm playing with fire here, but I was looking for a way to create an istream object for unbuffered input. Any ideas?
You can unbuffer an iostream with
http://www.cplusplus.com/reference/iostream/streambuf/pubsetbuf.html

But what are you really looking for? The ability to read keys without pressing ENTER?

On Windows you'll have to play with the SetConsoleMode() function (#include <windows.h>)
http://msdn.microsoft.com/en-us/library/ms686033(VS.85).aspx

(Both links have pretty good examples, but the last one is a little complex because it also gets window and mouse events from the keyboard. If you unbuffer cin you shouldn't have to worry about that.)

Hope this helps.
How should I use GetConsoleMode? I don't get handles or dwords or windows.h stuff in general. Thanks!
Here's an example:
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
#include <windows.h>

char pressanykey( const char *prompt )
  {
  DWORD        mode;
  HANDLE       hstdin;
  INPUT_RECORD inrec;
  DWORD        count;
  char         default_prompt[] = "Press the 'any' key...";
  char         result           = '\0';

  /* Set the console mode to no-echo, raw input, */
  /* and no window or mouse events.              */
  hstdin = GetStdHandle( STD_INPUT_HANDLE );
  if (hstdin == INVALID_HANDLE_VALUE
  || !GetConsoleMode( hstdin, &mode )
  || !SetConsoleMode( hstdin, 0 ))
    return result;

  if (!prompt) prompt = default_prompt;

  /* Instruct the user */
  WriteConsole(
    GetStdHandle( STD_OUTPUT_HANDLE ),
    prompt,
    lstrlen( prompt ),
    &count,
    NULL
    );

  FlushConsoleInputBuffer( hstdin );

  /* Wait for and get a single key PRESS */
  do ReadConsoleInput( hstdin, &inrec, 1, &count );
  while ((inrec.EventType != KEY_EVENT) || !inrec.Event.KeyEvent.bKeyDown);

  /* Remember which key the user pressed */
  result = inrec.Event.KeyEvent.uChar.AsciiChar;

  /* Wait for and get a single key RELEASE */
  do ReadConsoleInput( hstdin, &inrec, 1, &count );
  while ((inrec.EventType != KEY_EVENT) || inrec.Event.KeyEvent.bKeyDown);

  /* Restore the original console mode */
  SetConsoleMode( hstdin, mode );

  return result;
  }

The DOS PAUSE command doesn't wait for the key release, but as a separate process that isn't a problem. For use in your own code, it is often best to wait for the key release too...

Also, while C and C++ streams don't define flush on input streams, the Win32 console does. Hence line 30 to get rid of extraneous leftovers before beginning to wait for a key press.

I also added a return value to indicate which key was pressed...

Here's an example of how to use it:
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
/* ouch.c */

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>

/* ...same stuff as above goes here... */

const char* messages[ 3 ] =
  {
  "Press the 'any' key...",
  "\n\rAck! Not that one! Try again.",
  "\n\rWoah! Watch it! Press the ANY key!"
  };

int main()
  {
  int  i;
  char keys[ 4 ];

  for (i = 0; i < 3; i++)
    keys[ i ] = toupper( pressanykey( messages[ i ] ) );
  keys[ 3 ] = '\0';

  if (strcmp( keys, "ANY" ) == 0)
    printf( "\nFinally! Thank you.\n" );
  else
    printf( "\nOh forget it!\n" );

  printf( "\n\n\n\n\n" );
  pressanykey( "Press any key to quit. (Seriously this time.)" );

  return 0;
  }


A DWORD is a "double-word", or 32-bit integer. The name "dword" usually implies unsigned. So in C it would be 'unsigned int'. The Windows API makes extensive use of typedefs like this to make sure that the correct size items are used when interfacing with system DLLs.

A HANDLE is just an integer that represents some resource controlled by Windows, such as an edit box, or a button, or a file, or a process, or memory, etc. It is essentially a magic number.

The link I gave you lists the kinds of flags you want to use with SetConsoleMode(). Notice how in the example above I first saved the current console mode and last restored the console mode to its original state. In between I set the console mode to zero, or 'all flags off': unbuffered, no-echo, non-processed, keyboard-only input. Since the standard streams are (unless redirected) connected to the Windows console, modifying the console mode also appears to modify the function of cin. (It doesn't, but since the console is affected the behavior of cin reflects that.)

To test whether or not your standard stream is actually connected to a console, use GetConsoleMode() and check the return value. If zero (or false) then the standard input is not connected to a console.

Hope this helps.
Topic archived. No new replies allowed.