For a project I am working on, I need the program to be able to receive input from the user, but while they are inputting something, the program can continue in the loop.
For example:while (true)
{
if (userInput == true)
{
cin >> input
}
//DO SOMETHING
}
This would mean that //DO SOMETHING
would happen every loop, without the user pressing enter a million times.
kbhit()
and getch()
from conio.h, but that got very messy, and I don't like using conio.h for portability reasons etc. Also, it doesn't need to use cin
specifically, because there is a good chance it just wouldn't work with it, so any good solution that doesn't require me making my own input with a 'not very good' library, would be much appreciated.
Use cin. clear(); and cin. ignore(numeric_limits<streamsize>::max(), '\n'); to limit an input to int 's only.
Use the _getch() function to give you a character without waiting for the Enter key.
cin automatically generates a newline.
The standard C++ I/O libraries only have functions that read input from a stream, which means to get a string on a console, enter key should be pressed. If you want to get the input without pressing enter key, you have to use nonstandard functions like _getch() in <conio. h> in Windows.
It could be worth looking into multi-threading for this. I'm usually hesitant to suggest it, because multithreading pulls in a host of potential problems that can end up difficult to debug, but in this case they can be isolated fairly easily. I envision something like this:
#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>
int main() {
std::atomic<bool> interrupted;
int x;
int i = 0;
do {
interrupted.store(false);
// create a new thread that does stuff in the background
std::thread th([&]() {
while(!interrupted) {
// do stuff. Just as an example:
std::cout << i << std::flush;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
std::cin >> x;
// when input is complete, interrupt thread and wait for it to finish
interrupted.store(true);
th.join();
// apply x, then loop to make new thread to do stuff
i = x;
} while(x != -1); // or some other exit condition
}
At first glance this looks somewhat wasteful because it keeps spawning and throwing threads away, but user input takes, in computing terms, an eternity, so the overhead should not be prohibitive. More importantly, it does have the advantage of avoiding any suggestion of data races wholesale because the only means of communication between the main (input) loop and the background thread is the atomic interruption flag, and the application of x
to shared data happens when no thread is running that could race the main loop.
Disclaimer: the following seems to be working with gcc on Linux, however for some reasons it does not work with VC++ on Windows. The specifications appear to give a lot of leeway to the implementations here, and VC++ definitely takes advantage of it...
There are multiple functions available on any std::basic_istream
or its underlying std::basic_streambuf
.
In order to know if there is any character available for input, you may call in_avail
on std::basic_streambuf
:
if (std::cin.rdbuf() and std::cin.rdbuf()->in_avail() >= 0) {
}
in_avail
gives you the number of characters available without blocking, it returns -1
if there is no such character. Afterward, you can use the regular "formatted" read operations such as std::cin >> input
.
Otherwise, for unformatted reads, you can use readsome
from std::basic_istream
, which returns up to N characters available without blocking:
size_t const BufferSize = 512;
char buffer[BufferSize];
if (std::cin.readsome(buffer, BufferSize) >= 1) {
}
However it is noted that the implementation of this method is highly variable, so for a portable program it might not be that useful.
Note: as mentioned in the comment, the in_avail
approach might be spotty. I confirm it can work, however you first have to use an obscure feature of C++ IO streams: std::ios_base::sync_with_stdio(false)
which allows C++ streams to buffer input (and thus steal it from C's stdio buffers).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With