/*
* keypressed - Perform some calculation until the user presses some key.
*
* By default, standard input in C++ (and most terminals) is line-buffered:
* the terminal waits until you press Enter before sending the input to your
* program.
*
* Checking for a key press is not part of standard C++; it requires
* platform-specific APIs. On Windows, you can use _kbhit() from <conio.h>.
* The Microsoft-specific function name kbhit() is a deprecated alias for
* _kbhit(). The name is deprecated because it doesn't follow the Standard
* C rules for implementation-specific names. Therefore, Microsoft recommends
* you use _kbhit() instead.
* On Linux, you need termios to switch the terminal to raw mode (disable
* canonical input buffering) and check for a key press. Note that anything
* send to stdout while in raw mode is buffered and printed after leaving
* raw mode.
*
* If any type of portability is needed, use ncurses. It is a programming
* library for creating textual user interfaces (TUIs) that work across a
* wide variety of terminals.
*
* g++ -std=c++17 -Wpedantic -Wall -Wextra keypressed.cpp -o keypressed
*/
#include <iostream>
#include <chrono>
#include <thread>
#if defined(_WIN32) || defined(_WIN64)
// -------------------- WINDOWS VERSION --------------------
#include <conio.h>
char get_char() {
return _getch();
}
#else
// -------------------- LINUX / POSIX VERSION --------------------
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
class NonBlockingRawModeScope {
public:
NonBlockingRawModeScope() {
tcgetattr(STDIN_FILENO, &orig_termios);
termios raw = orig_termios;
raw.c_lflag &= ~(ICANON | ECHO); // disable canonical mode and echo
tcsetattr(STDIN_FILENO, TCSANOW, &raw);
// Make stdin non-blocking
int flags = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
}
~NonBlockingRawModeScope() {
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
}
private:
termios orig_termios;
};
int _kbhit() {
unsigned char ch;
int nread = read(STDIN_FILENO, &ch, 1);
if (nread == 1) {
ungetc(ch, stdin);
return 1;
}
return 0;
}
char get_char() {
return getchar();
}
#endif
int main() {
using namespace std::chrono_literals;
std::cout << "Press any key to stop...\n";
int counter = 0;
#if !defined(_WIN32) && !defined(_WIN64)
NonBlockingRawModeScope rawMode;
#endif
for (;;) {
if (_kbhit()) {
char c = get_char();
std::cout << "\nYou pressed: " << c << "\n";
break;
}
counter++;
std::cout << "Working... counter = " << counter << "\r" << std::flush;
std::this_thread::sleep_for(10ms);
}
return 0;
}