Capture characters from standard input without waiting for enter to be pressed

C++CInputstream

C++ Problem Overview


I can never remember how I do this because it comes up so infrequently for me. But in C or C++, what is the best way to read a character from standard input without waiting for a newline (press enter).

Also ideally it wouldn't echo the input character to the screen. I just want to capture keystrokes with out effecting the console screen.

C++ Solutions


Solution 1 - C++

That's not possible in a portable manner in pure C++, because it depends too much on the terminal used that may be connected with stdin (they are usually line buffered). You can, however use a library for that:

  1. conio available with Windows compilers. Use the _getch() function to give you a character without waiting for the Enter key. I'm not a frequent Windows developer, but I've seen my classmates just include <conio.h> and use it. See conio.h at Wikipedia. It lists getch(), which is declared deprecated in Visual C++.

  2. curses available for Linux. Compatible curses implementations are available for Windows too. It has also a getch() function. (try man getch to view its manpage). See Curses at Wikipedia.

I would recommend you to use curses if you aim for cross platform compatibility. That said, I'm sure there are functions that you can use to switch off line buffering (I believe that's called "raw mode", as opposed to "cooked mode" - look into man stty). Curses would handle that for you in a portable manner, if I'm not mistaken.

Solution 2 - C++

On Linux (and other unix-like systems) this can be done in following way:

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

char getch() {
        char buf = 0;
        struct termios old = {0};
        if (tcgetattr(0, &old) < 0)
                perror("tcsetattr()");
        old.c_lflag &= ~ICANON;
        old.c_lflag &= ~ECHO;
        old.c_cc[VMIN] = 1;
        old.c_cc[VTIME] = 0;
        if (tcsetattr(0, TCSANOW, &old) < 0)
                perror("tcsetattr ICANON");
        if (read(0, &buf, 1) < 0)
                perror ("read()");
        old.c_lflag |= ICANON;
        old.c_lflag |= ECHO;
        if (tcsetattr(0, TCSADRAIN, &old) < 0)
                perror ("tcsetattr ~ICANON");
        return (buf);
}

Basically you have to turn off canonical mode (and echo mode to suppress echoing).

Solution 3 - C++

I found this on another forum while looking to solve the same problem. I've modified it a bit from what I found. It works great. I'm running OS X, so if you're running Microsoft, you'll need to find the correct system() command to switch to raw and cooked modes.

#include <iostream> 
#include <stdio.h>  
using namespace std;  

int main() { 
  // Output prompt 
  cout << "Press any key to continue..." << endl; 

  // Set terminal to raw mode 
  system("stty raw"); 

  // Wait for single character 
  char input = getchar(); 

  // Echo input:
  cout << "--" << input << "--";

  // Reset terminal to normal "cooked" mode 
  system("stty cooked"); 

  // And we're out of here 
  return 0; 
}

Solution 4 - C++

CONIO.H

the functions you need are:

int getch();
Prototype
    int _getch(void); 
Description
    _getch obtains a character  from stdin. Input is unbuffered, and this
    routine  will  return as  soon as  a character is  available  without 
    waiting for a carriage return. The character is not echoed to stdout.
    _getch bypasses the normal buffering done by getchar and getc. ungetc 
    cannot be used with _getch. 
Synonym
    Function: getch 


int kbhit();
Description
    Checks if a keyboard key has been pressed but not yet read. 
Return Value
    Returns a non-zero value if a key was pressed. Otherwise, returns 0.

libconio http://sourceforge.net/projects/libconio

or

Linux c++ implementation of conio.h http://sourceforge.net/projects/linux-conioh

Solution 5 - C++

If you are on windows, you can use PeekConsoleInput to detect if there's any input,

HANDLE handle = GetStdHandle(STD_INPUT_HANDLE);
DWORD events;
INPUT_RECORD buffer;
PeekConsoleInput( handle, &buffer, 1, &events );

then use ReadConsoleInput to "consume" the input character ..

PeekConsoleInput(handle, &buffer, 1, &events);
if(events > 0)
{
	ReadConsoleInput(handle, &buffer, 1, &events);	
	return buffer.Event.KeyEvent.wVirtualKeyCode;
}
else return 0

to be honest this is from some old code I have, so you have to fiddle a bit with it.

The cool thing though is that it reads input without prompting for anything, so the characters are not displayed at all.

Solution 6 - C++

#include <conio.h>

if (kbhit() != 0) {
    cout << getch() << endl;
}

This uses kbhit() to check if the keyboard is being pressed and uses getch() to get the character that is being pressed.

Solution 7 - C++

I use kbhit() to see if a char is present and then getchar() to read the data. On windows, you can use "conio.h". On linux, you will have to implement your own kbhit().

See code below:

// kbhit
#include <stdio.h>
#include <sys/ioctl.h> // For FIONREAD
#include <termios.h>
#include <stdbool.h>

int kbhit(void) {
    static bool initflag = false;
    static const int STDIN = 0;

    if (!initflag) {
        // Use termios to turn off line buffering
        struct termios term;
        tcgetattr(STDIN, &term);
        term.c_lflag &= ~ICANON;
        tcsetattr(STDIN, TCSANOW, &term);
        setbuf(stdin, NULL);
        initflag = true;
    }

    int nbbytes;
    ioctl(STDIN, FIONREAD, &nbbytes);  // 0 is STDIN
    return nbbytes;
}

// main
#include <unistd.h>

int main(int argc, char** argv) {
    char c;
    //setbuf(stdout, NULL); // Optional: No buffering.
    //setbuf(stdin, NULL);  // Optional: No buffering.
    printf("Press key");
    while (!kbhit()) {
        printf(".");
        fflush(stdout);
        sleep(1);
    }
    c = getchar();
    printf("\nChar received:%c\n", c);
    printf("Done.\n");

    return 0;
}

Solution 8 - C++

ncurses provides a nice way to do this! Also this is my very first post (that I can remember), so any comments at all are welcome. I will appreciate useful ones, but all are welcome!

to compile: g++ -std=c++11 -pthread -lncurses .cpp -o

#include <iostream>
#include <ncurses.h>
#include <future>

char get_keyboard_input();

int main(int argc, char *argv[])
{
    initscr();
    raw();
    noecho();
    keypad(stdscr,true);

    auto f = std::async(std::launch::async, get_keyboard_input);
    while (f.wait_for(std::chrono::milliseconds(20)) != std::future_status::ready)
    {
        // do some work
    }

    endwin();
    std::cout << "returned: " << f.get() << std::endl;
    return 0;
}

char get_keyboard_input()
{
    char input = '0';
    while(input != 'q')
    {
        input = getch();
    }
    return input;
}

Solution 9 - C++

Assuming Windows, take a look at the ReadConsoleInput function.

Solution 10 - C++

C and C++ take a very abstract view of I/O, and there is no standard way of doing what you want. There are standard ways to get characters from the standard input stream, if there are any to get, and nothing else is defined by either language. Any answer will therefore have to be platform-specific, perhaps depending not only on the operating system but also the software framework.

There's some reasonable guesses here, but there's no way to answer your question without knowing what your target environment is.

Solution 11 - C++

The closest thing to portable is to use the ncurses library to put the terminal into "cbreak mode". The API is gigantic; the routines you'll want most are

  • initscr and endwin
  • cbreak and nocbreak
  • getch

Good luck!

Solution 12 - C++

Since previous solutions here don't work cross-platform and have trouble with special keys, here is my solution that works on both Windows and Linux and uses a minimum of external libraries (Windows.h for Windows and sys/ioctl.h+termios.h for Linux).

For ASCII characters (newline/tab/space/backspace/delete, !"#$%&'()*+,-./0-9:;<=>?@A-Z[]^_`a-z{|}~üäÄöÖÜßµ´§°¹³²), the ASCII codes (positive numbers) are returned and for special keys (arrow keys, page up/down, pos1/end, escape, insert, F1-F12), the negative of Windows Virtual-Key codes (negative numbers) are returned.

#include <iostream>
#include <string>
#include <thread> // contains <chrono>
using namespace std;

void println(const string& s="") {
	cout << s << endl;
}
void sleep(const double t) {
	if(t>0.0) this_thread::sleep_for(chrono::milliseconds((int)(1E3*t+0.5)));
}



// ASCII codes (key>0): 8 backspace, 9 tab, 10 newline, 27 escape, 127 delete, !"#$%&'()*+,-./0-9:;<=>?@A-Z[]^_`a-z{|}~üäÄöÖÜßµ´§°¹³²
// control key codes (key<0): -38/-40/-37/-39 up/down/left/right arrow, -33/-34 page up/down, -36/-35 pos1/end
// other key codes (key<0): -45 insert, -144 num lock, -20 caps lock, -91 windows key, -93 kontext menu key, -112 to -123 F1 to F12
// not working: ¹ (251), num lock (-144), caps lock (-20), windows key (-91), kontext menu key (-93), F11 (-122)
#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#include <Windows.h>
int key_press() { // not working: F11 (-122, toggles fullscreen)
	KEY_EVENT_RECORD keyevent;
	INPUT_RECORD irec;
	DWORD events;
	while(true) {
		ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &irec, 1, &events);
		if(irec.EventType==KEY_EVENT&&((KEY_EVENT_RECORD&)irec.Event).bKeyDown) {
			keyevent = (KEY_EVENT_RECORD&)irec.Event;
			const int ca = (int)keyevent.uChar.AsciiChar;
			const int cv = (int)keyevent.wVirtualKeyCode;
			const int key = ca==0 ? -cv : ca+(ca>0?0:256);
			switch(key) {
				case  -16: continue; // disable Shift
				case  -17: continue; // disable Ctrl / AltGr
				case  -18: continue; // disable Alt / AltGr
				case -220: continue; // disable first detection of "^" key (not "^" symbol)
				case -221: continue; // disable first detection of "`" key (not "`" symbol)
				case -191: continue; // disable AltGr + "#"
				case  -52: continue; // disable AltGr + "4"
				case  -53: continue; // disable AltGr + "5"
				case  -54: continue; // disable AltGr + "6"
				case  -12: continue; // disable num block 5 with num lock deactivated
				case   13: return  10; // enter
				case  -46: return 127; // delete
				case  -49: return 251; // ¹
				case    0: continue;
				case    1: continue; // disable Ctrl + a (selects all text)
				case    2: continue; // disable Ctrl + b
				case    3: continue; // disable Ctrl + c (terminates program)
				case    4: continue; // disable Ctrl + d
				case    5: continue; // disable Ctrl + e
				case    6: continue; // disable Ctrl + f (opens search)
				case    7: continue; // disable Ctrl + g
				//case    8: continue; // disable Ctrl + h (ascii for backspace)
				//case    9: continue; // disable Ctrl + i (ascii for tab)
				case   10: continue; // disable Ctrl + j
				case   11: continue; // disable Ctrl + k
				case   12: continue; // disable Ctrl + l
				//case   13: continue; // disable Ctrl + m (breaks console, ascii for new line)
				case   14: continue; // disable Ctrl + n
				case   15: continue; // disable Ctrl + o
				case   16: continue; // disable Ctrl + p
				case   17: continue; // disable Ctrl + q
				case   18: continue; // disable Ctrl + r
				case   19: continue; // disable Ctrl + s
				case   20: continue; // disable Ctrl + t
				case   21: continue; // disable Ctrl + u
				case   22: continue; // disable Ctrl + v (inserts clipboard)
				case   23: continue; // disable Ctrl + w
				case   24: continue; // disable Ctrl + x
				case   25: continue; // disable Ctrl + y
				case   26: continue; // disable Ctrl + z
				default: return key; // any other ASCII/virtual character
			}
		}
	}
}
#elif defined(__linux__)
#include <sys/ioctl.h>
#include <termios.h>
int key_press() { // not working: ¹ (251), num lock (-144), caps lock (-20), windows key (-91), kontext menu key (-93)
	struct termios term;
	tcgetattr(0, &term);
	while(true) {
		term.c_lflag &= ~(ICANON|ECHO); // turn off line buffering and echoing
		tcsetattr(0, TCSANOW, &term);
		int nbbytes;
		ioctl(0, FIONREAD, &nbbytes); // 0 is STDIN
		while(!nbbytes) {
			sleep(0.01);
			fflush(stdout);
			ioctl(0, FIONREAD, &nbbytes); // 0 is STDIN
		}
		int key = (int)getchar();
		if(key==27||key==194||key==195) { // escape, 194/195 is escape for °ß´äöüÄÖÜ
			key = (int)getchar();
			if(key==91) { // [ following escape
				key = (int)getchar(); // get code of next char after \e[
				if(key==49) { // F5-F8
					key = 62+(int)getchar(); // 53, 55-57
					if(key==115) key++; // F5 code is too low by 1
					getchar(); // take in following ~ (126), but discard code
				} else if(key==50) { // insert or F9-F12
					key = (int)getchar();
					if(key==126) { // insert
						key = 45;
					} else { // F9-F12
						key += 71; // 48, 49, 51, 52
						if(key<121) key++; // F11 and F12 are too low by 1
						getchar(); // take in following ~ (126), but discard code
					}
				} else if(key==51||key==53||key==54) { // delete, page up/down
					getchar(); // take in following ~ (126), but discard code
				}
			} else if(key==79) { // F1-F4
				key = 32+(int)getchar(); // 80-83
			}
			key = -key; // use negative numbers for escaped keys
		}
		term.c_lflag |= (ICANON|ECHO); // turn on line buffering and echoing
		tcsetattr(0, TCSANOW, &term);
		switch(key) {
			case  127: return   8; // backspace
			case  -27: return  27; // escape
			case  -51: return 127; // delete
			case -164: return 132; // ä
			case -182: return 148; // ö
			case -188: return 129; // ü
			case -132: return 142; // Ä
			case -150: return 153; // Ö
			case -156: return 154; // Ü
			case -159: return 225; // ß
			case -181: return 230; // µ
			case -167: return 245; // §
			case -176: return 248; // °
			case -178: return 253; // ²
			case -179: return 252; // ³
			case -180: return 239; // ´
			case  -65: return -38; // up arrow
			case  -66: return -40; // down arrow
			case  -68: return -37; // left arrow
			case  -67: return -39; // right arrow
			case  -53: return -33; // page up
			case  -54: return -34; // page down
			case  -72: return -36; // pos1
			case  -70: return -35; // end
			case    0: continue;
			case    1: continue; // disable Ctrl + a
			case    2: continue; // disable Ctrl + b
			case    3: continue; // disable Ctrl + c (terminates program)
			case    4: continue; // disable Ctrl + d
			case    5: continue; // disable Ctrl + e
			case    6: continue; // disable Ctrl + f
			case    7: continue; // disable Ctrl + g
			case    8: continue; // disable Ctrl + h
			//case    9: continue; // disable Ctrl + i (ascii for tab)
			//case   10: continue; // disable Ctrl + j (ascii for new line)
			case   11: continue; // disable Ctrl + k
			case   12: continue; // disable Ctrl + l
			case   13: continue; // disable Ctrl + m
			case   14: continue; // disable Ctrl + n
			case   15: continue; // disable Ctrl + o
			case   16: continue; // disable Ctrl + p
			case   17: continue; // disable Ctrl + q
			case   18: continue; // disable Ctrl + r
			case   19: continue; // disable Ctrl + s
			case   20: continue; // disable Ctrl + t
			case   21: continue; // disable Ctrl + u
			case   22: continue; // disable Ctrl + v
			case   23: continue; // disable Ctrl + w
			case   24: continue; // disable Ctrl + x
			case   25: continue; // disable Ctrl + y
			case   26: continue; // disable Ctrl + z (terminates program)
			default: return key; // any other ASCII character
		}
	}
}
#endif // Windows/Linux

Finally, here is an example on how to use it:

int main() {
	while(true) {
		const int key = key_press(); // blocks until a key is pressed
		println("Input is: "+to_string(key)+", \""+(char)key+"\"");
	}
	return 0;
}

Solution 13 - C++

I always wanted a loop to read my input without pressing return key. this worked for me.

#include<stdio.h>
 main()
 {
   char ch;
    system("stty raw");//seting the terminal in raw mode
    while(1)
     {
     ch=getchar();
      if(ch=='~'){          //terminate or come out of raw mode on "~" pressed
      system("stty cooked");
     //while(1);//you may still run the code 
     exit(0); //or terminate
     }
       printf("you pressed %c\n ",ch);  //write rest code here
      }

    }

Solution 14 - C++

The following is a solution extracted from Expert C Programming: Deep Secrets, which is supposed to work on SVr4. It uses stty and ioctl.

#include <sys/filio.h>
int kbhit()
{
 int i;
 ioctl(0, FIONREAD, &i);
 return i; /* return a count of chars available to read */
}
main()
{
 int i = 0;
 intc='';
 system("stty raw -echo");
 printf("enter 'q' to quit \n");
 for (;c!='q';i++) {
    if (kbhit()) {
        c=getchar();
       printf("\n got %c, on iteration %d",c, i);
    }
}
 system("stty cooked echo");
}

Solution 15 - C++

works for me on windows:

#include <conio.h>
char c = _getch();

Solution 16 - C++

You can do it portably using SDL (the Simple DirectMedia Library), though I suspect you may not like its behavior. When I tried it, I had to have SDL create a new video window (even though I didn't need it for my program) and have this window "grab" almost all keyboard and mouse input (which was okay for my usage but could be annoying or unworkable in other situations). I suspect it's overkill and not worth it unless complete portability is a must--otherwise try one of the other suggested solutions.

By the way, this will give you key press and release events separately, if you're into that.

Solution 17 - C++

Variant of ssinfod's answer for Linux that's a little cleaner for my tastes, implemented for wcout and wchar_t, and erases invalid characters without bugs.

#include <functional>

//For Linux kbhit(). For Windows, use conio.h.
#ifdef __unix__
  #include <sys/ioctl.h> //For FIONREAD.
  #include <termios.h>

  //Call this at program start to setup for kbhit.
  void initTerminalInput()
  {
    //Disable internal buffering.
    std::wcout << std::unitbuf;

    //Turn off line buffering.
    struct termios term;
    tcgetattr(0, &term);
    term.c_lflag &= ~ICANON;
    tcsetattr(0, TCSANOW, &term);
    setbuf(stdin, NULL);
  }

  //Returns 0 if there's no input character to read.
  int kbhit()
  {
    static int nbbytes;
    ioctl(0, FIONREAD, &nbbytes);
    return nbbytes;
  }
#endif

//Waits for and retrieves a single validated character, calling a validation function on each character entered and
//erasing any that are invalid (when the validation function returns false).
static wchar_t getWChar(std::function<bool(wchar_t)> validationFunction)
{
  static wchar_t inputWChar;
  do
  {
    //Wait until there's an input character.
    while (!kbhit())
    {
    }
    inputWChar = getwchar();
    //Validate the input character.
    if (validationFunction(inputWChar))
    {
      //Valid.
      break;
    }
    else
    {
      //Erase the invalid character.
      std::wcout << L"\b \b";
    }
  } while (true);
  return inputWChar;
}

In the below example, I wanted for the user to enter either 1, 2, or 3. Any other characters entered will not be displayed, and it will wait until one of the valid characters is pressed:

int main()
{
  #ifdef __unix__
    initTerminalInput();
  #endif

  getWChar([] (wchar_t inputWChar)
  {
    return (inputWChar >= L'1' && inputWChar <= L'3');
  });

  return 0;
}

Solution 18 - C++

Here's a version that doesn't shell out to the system (written and tested on macOS 10.14)

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

char* getStr( char* buffer , int maxRead ) {
  int  numRead  = 0;
  char ch;
  
  struct termios old = {0};
  struct termios new = {0};
  if( tcgetattr( 0 , &old ) < 0 )        perror( "tcgetattr() old settings" );
  if( tcgetattr( 0 , &new ) < 0 )        perror( "tcgetaart() new settings" );
  cfmakeraw( &new );
  if( tcsetattr( 0 , TCSADRAIN , &new ) < 0 ) perror( "tcssetattr makeraw new" );

  for( int i = 0 ; i < maxRead ; i++)  {
    ch = getchar();
    switch( ch )  {
      case EOF: 
      case '\n':
      case '\r':
        goto exit_getStr;
        break;
        
      default:
        printf( "%1c" , ch );
        buffer[ numRead++ ] = ch;
        if( numRead >= maxRead )  {
          goto exit_getStr;
        }
        break;
    }
  }
  
exit_getStr:
  if( tcsetattr( 0 , TCSADRAIN , &old) < 0)   perror ("tcsetattr reset to old" );
  printf( "\n" );   
  return buffer;
}


int main( void ) 
{
  const int maxChars = 20;
  char      stringBuffer[ maxChars+1 ];
  memset(   stringBuffer , 0 , maxChars+1 ); // initialize to 0
  
  printf( "enter a string: ");
  getStr( stringBuffer , maxChars );
  printf( "you entered: [%s]\n" , stringBuffer );
}

Solution 19 - C++

ON WINDOWS I do so:

#include <Windows.h>
int main()
{
    system("PAUSE>NUL");
    if (GetKeyState(0x41/*(the 'A' key, choosen e.g.)*/) & (0xff80/*That stands for "Default state / Key Down"*/)) {
        //whatever I want to do after 'A' is pressed
    }
}

Here can be found a list of keys with its own hex value for each: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes

Solution 20 - C++

Pipe demo: how to read keyboard presses from a system call pipe in C

> Also ideally it wouldn't echo the input character to the screen. I just want to capture keystrokes with out effecting the console screen.

To do this on Linux you can use the following bash command:

read -sn1 c && printf "You Pressed: %s\n" "$c"

See my answer here for details on this: shell script respond to keypress.

So, to do this in C or C++ on Linux, you simply need to call the above bash command via a system call through a pipe with popen() and fgets() so you can read the output from the bash command.

Here is a full example which runs fine on Linux in both C and C++:

read_system_call_via_pipe__keypress.c:

#include <stdbool.h> // For `true` (`1`) and `false` (`0`) macros in C
#include <stdint.h>  // For `uint8_t`, `int8_t`, etc.
#include <stdio.h>   // For `printf()`
#include <stdlib.h>

#define BUFSIZE 32

// Read a keyboard key press and return the character pressed, or a negative
// number in the event of an error.
// NB: for help reading output from system calls, see here:
//  1. https://stackoverflow.com/a/28971647/4561887
//  2. https://stackoverflow.com/a/18297075/4561887
char getKeypress()
{
    // This bash cmd is from my answer here:
    // https://stackoverflow.com/a/70979348/4561887
    const char* cmd = "bash -c 'read -s -n1 c && printf \"%s\" \"$c\"'";
    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        printf("\nError opening pipe!\n");
        return -1;
    }

    char buf[BUFSIZE] = {0};
    char* retval1 = fgets(buf, BUFSIZE, fp);
    if (retval1 == NULL)
    {
        printf("\nFailed to read cmd response.\n");
        return -2;
    }

    // See meaning of this return value here:
    // https://stackoverflow.com/questions/43116/how-can-i-run-an-external-program-from-c-and-parse-its-output/28971647#comment60311936_28971647
    int retval2 = pclose(fp);
    if (retval2 == -1)
    {
        printf("\nError obtaining the cmd's exit status code.\n");
        return -3;
    }
    else if (retval2 != 0)
    {
        printf("\nCommand exited with exit status code %i.\n", retval2);
        return -4;
    }

    char keyPressed = buf[0];
    return keyPressed;
}

// int main(int argc, char *argv[])  // alternative prototype
int main()
{
    printf("Press any key to continue: ");
    fflush(stdout);
    char keyPressed = getKeypress();
    if (keyPressed > 0)
    {
        printf("\nKey pressed = %c\n", keyPressed);
    }

    return 0;
}

The C and C++ compile and run commands are part of the output below. Here are some demos:

In C:

eRCaGuy_hello_world/c$ gcc -Wall -Wextra -Werror -O3 -std=gnu17 read_keypress_system_call.c -o bin/a && bin/a
Press any key to continue:
Key pressed = P

OR, in C++:

eRCaGuy_hello_world/c$ g++ -Wall -Wextra -Werror -O3 -std=c++17 read_keypress_system_call.c -o bin/a && bin/a
Press any key to continue:
Key pressed = u

See also:

  1. To take this one step further, see my other answer here where I detect and parse 3 chars at a time in order to detect arrow key presses Up, Down, Left, or Right: Read Key pressings in C ex. Arrow keys, Enter key

References:

  1. How I learned to read from a pipe to get system call output:
    1. How can I run an external program from C and parse its output?
    2. Is there a way to obtain the output of a linux command(like ifconfig) on a .txt file using a C program? [duplicate]
    3. How to compile and use popen() in C: use -std=gnu17 instead of -std=c17: popen implicitly declared even though #include is added
  2. [my answer] How to read without blocking, via bash: shell script respond to keypress
  3. [my answer] How do I read in the Enter key as an input in C?

All 3 Q&As on this topic

  1. Capture characters from standard input without waiting for enter to be pressed
  2. C non-blocking keyboard input
  3. How to avoid pressing Enter with getchar() for reading a single character only?

Solution 21 - C++

I was running into this same issue. Here is a small solution for windows console using cygwin g++ with if(GetKeyState(keycode) & bitANDcompare){};.

#include <windows.h>
#include <fstream>
#include <iostream>

using namespace std;
void clear() {
    COORD topLeft  = { 0, 0 };
    HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO screen;
    DWORD written;

    GetConsoleScreenBufferInfo(console, &screen);
    FillConsoleOutputCharacterA(
        console, ' ', screen.dwSize.X * screen.dwSize.Y, topLeft, &written
    );
    FillConsoleOutputAttribute(
        console, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE,
        screen.dwSize.X * screen.dwSize.Y, topLeft, &written
    );
    SetConsoleCursorPosition(console, topLeft);
}

class Keyclick{
	private:
	int key;
	char id;
	public:
	bool keydown = false;
	Keyclick(int key1, char id1){
		key=key1;
		id=id1;
	};
	void watch(){
		if(keydown==false){
			if(GetKeyState(key) & 0x8000 ){
				cout << id;
				cout << "  pressed.\r\n";
				keydown = true;
			}
		}
		if(keydown == true){
			if(!(GetKeyState(key) & 0x8000)) {
				cout << "released!!!!!!!!!!\r\n";
				keydown = false;
				clear();
			}
		}
	};
};

int main()
{
	bool primaryloop =true;
	Keyclick keysp(VK_SPACE,'S');
	Keyclick keyw(0x57,'w');
	Keyclick keya(0x41,'a');
	Keyclick keys(0x53,'s');
	Keyclick keyd(0x44,'d');
	Keyclick keyesc(VK_ESCAPE,'E');
	
    while(primaryloop){
		keysp.watch();
		keyw.watch();
		keya.watch();
		keys.watch();
		keyd.watch();
		keyesc.watch();
		
		if(keyesc.keydown){
			primaryloop=false;
		};		
    }
    return 0;
}

https://github.com/wark77/windows_console_keypoller/blob/main/getkeystate_SOLUTION01.cpp

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAdamView Question on Stackoverflow
Solution 1 - C++Johannes Schaub - litbView Answer on Stackoverflow
Solution 2 - C++anonView Answer on Stackoverflow
Solution 3 - C++cwhiiiView Answer on Stackoverflow
Solution 4 - C++dddomodossolaView Answer on Stackoverflow
Solution 5 - C++hasenView Answer on Stackoverflow
Solution 6 - C++Joseph DykstraView Answer on Stackoverflow
Solution 7 - C++ssinfodView Answer on Stackoverflow
Solution 8 - C++AngryDaneView Answer on Stackoverflow
Solution 9 - C++TritiumView Answer on Stackoverflow
Solution 10 - C++David ThornleyView Answer on Stackoverflow
Solution 11 - C++Norman RamseyView Answer on Stackoverflow
Solution 12 - C++ProjectPhysXView Answer on Stackoverflow
Solution 13 - C++Setu GuptaView Answer on Stackoverflow
Solution 14 - C++PolyThinkerView Answer on Stackoverflow
Solution 15 - C++user1438233View Answer on Stackoverflow
Solution 16 - C++RuchiraView Answer on Stackoverflow
Solution 17 - C++AndrewView Answer on Stackoverflow
Solution 18 - C++Jeff SzuhayView Answer on Stackoverflow
Solution 19 - C++thomasView Answer on Stackoverflow
Solution 20 - C++Gabriel StaplesView Answer on Stackoverflow
Solution 21 - C++wark77View Answer on Stackoverflow