How do I clear user input (cin) that occurred while the process was blocked? - c++

I have a C++ program that takes input from the user on std::cin. At some points it needs to call a function that opens a GUI window with which the user can interact. While this window is open, my application is blocked. I noticed that if the user types anything into my application's window while the other window is open, then nothing happens immediately, but when control returns to my application those keystrokes are all acted upon at once. This is not desirable. I would like for all keystrokes entered while the application is blocked to be ignored; alternatively, a way to discard them all upon the application regaining control, but retaining the capability to react to keystrokes that occur after that.
There are various questions on Stack Overflow that explain how to clear a line of input, but as far as I can tell they tend to assume things like "the unwanted input only lasts until the next newline character". In this case this might not be so, because the user could press enter several times while the application is blocked. I have tried a variety of methods (getline(), get(), readsome(), ...) but they generally seem not to detect when cin is temporarily exhausted. Rather, they wait for the user to continue supplying content for cin. For example, if I use cin.ignore(n), then not only is everything typed while the GUI window was open ignored, but the program keeps waiting afterwards while the user types content until a total of n characters have been typed. That's not what I want - I want to ignore characters based on where in time they occurred, not where in the input stream they occur.
What is the idiom for "exhaust everything that's in cin right now, but then stop looking for more stuff"? I don't know what to search for to solve this.
I saw this question, which might be similar and has an answer, but the answer asks for the use of <termios.h>, which isn't available on Windows.

There is no portable way to achieve what you are trying to do. You basically need to set the input stream to non-blocking state and keep reading as long as there are any characters.
get() and getline() will just block until there is enough input to satisfy the request. readsome() only deals with the stream's internal buffer and is only use to non-blockingly extract what was already read from the streams internal buffer.
On POSIX systems you'd just set the O_NONBLOCK with fcntl() and keep read()ing from file descriptor 0 until the read returns a value <= 0 (if it is less than 0 there was an error; otherwise there is no input). Since the OS normally buffers input on a console, you'd also need to set the stream to non-canonical mode (using tcsetattr()). Once you are done you'd probably restore the original settings.
How to something similar on non-POSIX systems I don't know.

Related

QTextEdit for input and output

I am considering using QTextEdit as console-like IO element (for serial data).
The problem with this approach is that (user) input and (communication) output are mixed and they might not be synchronous.
To detect new user input, it might be possible to store and compare plainText on certain input events, e.g. when Enter/Return is pressed.
Another approach might be to use the QTextEdit as view only for separately managed input and output buffers. This could also simplify the problem of potentially asynchronous data (device sends characters while user is typing, very unlikely in my case).
However, even merging the two "streams" by single-character timestamp holds potential for conflict.
Is there a (simple) solution or should I simply use separate and completely independent input/output areas?
Separate I/O areas is the simplest way to proceed if your UI is command driven and the input is line-oriented.
Alternatively, the remote device can be providing the echo, without a local echo. The remote device will then echo the characters back when it makes sense, to maintain coherent display.
You can also display a local line editing buffer to provide user feedback in case the remote echo was delayed or unavailable. That buffer would be only for feedback and have no impact on other behavior of the terminal; all keystrokes would be immediately sent to the remote device.

How can I flush stdin? (environment: Mingw compiler, running in xterm or mintty of Cygwin)

There are two ways that I know to flush stdin:
(1) bool FlushConsoleInputBuffer(_In_ HANDLE hConsoleInput);
(2) fflush (stdin);
However, in my environment:
Compiler: MinGW g++
Running in: Windows, Cygwin xterm or Cygwin mintty
Neither of them works.
What can I do?
Note: FlushConsoleInputBuffer() works if my program runs under dos prompt window. In addition, FlushConsoleInputBuffer() nicely returns false, when it runs on Cygwin xterm or mintty.
--UPDATE--
I suspect that Cygwin handles stdin separately than Windows native stdin, which make FlushConsoleInputBuffer() fail.
#wallyk: yes. 'flush' means dropping all unread buffered inputs.
--UPDATE-- (final answer accepted and reason)
Tony D is right. The problem is that Cygwin terminal is a unix-like terminal, which allows editing before 'ENTER' key is hit. Thus any partial input must be buffered and will never be passed to stdin before the 'ENTER' key is hit, since it expects editing commands. I guess it should be possible to overcome this by setting terminal to raw mode (not experimented). Yet the editing feature will be lost in the raw mode.
fflush is meant to be used with an output stream. The behavior of fflush(stdin) is undefined. See http://en.cppreference.com/w/cpp/io/c/fflush.
If you use std::cin to access stdin, you can use std::istream::ignore() to ignore the contents of the stream up to a given number of characters or a given character.
Example:
// Ignore the rest of the line.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Working code: http://ideone.com/Z6zLue
If you are using stdin to access the input stream, you can use the following to ignore the rest of the line.
while ( (c = fgetc(stdin)) != '\n' && c != EOF);
Working code: http://ideone.com/gg0Az2
Discarding exactly and only the data currently buffered/available to stdin isn't supported using only C++ Standard library features.
Most of the time, programmers just ignore (see example at the bottom of that page) the rest of a problematic line then try the next buffered line. If you're concerned there may be a lot of problematic lines - for example, that the user may have cut-and-pasted pages of nonsense that you want to discard, but then you do want to give them a chance to enter further lines, you need to use an OS-specific function to work out when a read on stdin would block. You'd then ignore lines until that would-block condition is true.
select and poll are two such operations that work on most Operating Systems, but from memory they're only defined for socket streams on Windows so of no use to you. Cygwin may or may not support them somehow; if you want to try it - you would ignore lines as long as the stdin file descriptor (which is 0) tests readable. You'll find lots of other Q&A discussing how to see if there's input available: e.g. checking data availability before calling std::getline, Check if stdin is empty, Win32 - read from stdin with timeout
Keep in mind that your terminal program is probably internally buffering what you type until you press ENTER, so at most your program can clear the earlier lines but not a line the user's partially typed (though you could use some heuristic to discard it after it's sent to your program's stdin).
UPDATE
Cruder alternatives that might be good enough in some circumstances:
save the now() time, then loop calling getline(std::cin, my_string) until either it fails (e.g. EOF on stdin) or the time between reads is greater than some threshold - say half a second; that way it's likely to consume the already-buffered but unwanted input, and yet ENTER for further hand-typed user input's likely to happen after the discarding loop's terminated: you could prompt ala std::cout >> "bad input discarded - you may press ^U to clear your input buffer if it contains unwanted text...\n"; (Control-U works for many terminals, but check your own)
have a particular string like say "--reset--" that the user knows they can type to stop discarding lines and switch back to processing future lines

C++ stdin occasionally garbled

I've been experiencing a strange occasionally occurring bug for the last few days.
I have a console application that also displays a window opened with SDL for graphical output continuously running three threads. The main thread runs the event loop, and processes the console input. The second thread uses std::cin.getline to get the console input. This second thread, however, is also responsible for outputting logging information, which can be produced when the user clicks somewhere on the SDL window.
These log messages are sent to a mutex-protected stringstream regularly checked by thread 2. If there are log messages it deletes the prompt, outputs them and then prints a new prompt. Due to this it can't afford to block on getline, so this thread spawns the third thread that peeks cin and signals via an atomic when there's data to be got from the input stream, at which point getline is called and the input is passed to the logic on the main thread.
Here's the bit I haven't quite worked out, about 1 in 30 of these fails since the program doesn't receive exactly the same input as was typed into the terminal. You can see what I mean in the images here, the first line is what was type and the second is the Lua stacktrace due to receiving different (incorrect) input.
This occurs whether I use rlwrap or not. Is this due to peek and getline hitting the input stream at the same time? (This is possible as the peek loop just looks like:
while(!exitRequested_)
{
if (std::cin.peek())
inputAvailable_ = true; // this is atomic
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
Any thoughts? I looked at curses quickly, but it looks like quite a lot of effort to use. I've never heard of get line garbling stuff before. But I also printed every string that was received for a while and they matched what Lua is reporting.
As #davmac suggested, peek appears to have been interfering with getline. My assumption would be that this is linked to peek taking a character and then putting it back at the same time as getline takes the buffer.
Whatever the underlying cause of the issue is, I am >98% sure that the problem has been fixed by implementing the fix davmac suggested.
In several hours of use I have had no issues.
Moral, don't concurrently access cin, even if one of the functions doesn't modify the stream.
(Note, the above happened on both g++ and clang++ so I assume that it's just linked to the way the std library is frequently implemented).
As #DavidSchwartz pointed out, concurrent access to streams is explicitly prohibited, so that clearly explains why the fix works.

How to interrupt loop/process using terminal input in C++ on a Linux application

I am writing a Linux command line application that ultimately leads to data acquisition from a piece of hardware. The nature of the data acquisition is that it will feed data to the program consistently at some defined data rate. Once the user enters into RxData (the receive loop), we do not want to stop unless we get a command from the terminal to tell it to stop. The problem I foresee is that using getchar() will hang the loop every iteration of the while loop because the program will expect the user to enter input. Am I wrong in this behavior?
On a side note, I know that when working with embedded devices, you can simply check a register to see if the buffer has increased and use that to determine whether or not to read from the buffer or not. I do not have that luxury on a Linux application (or do I?). Does some such function (let's call it getCharAvailable) which I can run, check if data has been input, and THEN signal my program to stop acquiring data?
I can't simply use SIGINT because I need to signal to the hardware to stop data acquisition as well as add a header to the recorded data. There needs to be a signal to stop acquisition.
In Linux (or any other Unix flavour), you can use select to look if there is available data on 2 (or more) file descriptors, sockets or any other thing that can be read. (It is the reason why this system call exists ...)
use the ncurse library and use getch in non-delay mode

How do I separate input from output in a C++ console application? Can I have two cursors?

I'm coming from C and don't have too much programming knowledge, so bear with me if my idea is nonsense.
Right now, I'm trying to write a simple threaded application with double-buffered console output. I've got a thread which resets the cursor position, draws the buffer and then waits n milliseconds:
gotoxy(0, 0);
std::cout << *draw_buffer;
std::this_thread::sleep_for(std::chrono::milliseconds(33));
This works perfectly well. The buffer is filled independently by another thread and also causes no problems.
Now I want the user to be able to feed the application information. However, my drawing thread always puts the cursor back to the start, so the user input and the application output will interfere. I'm aware there are libraries like curses, but I'd prefer to write this myself, if possible. Unfortunately, I haven't found any solution to this. I guess there is no way to have two console cursors moving independently? How else could I approach this problem?
I think what you will need to do two things:
Create a mutex that controls which thread is writing to stdout.
Change the input mode so that when you invoke getchar, it returns immediately (rather than waiting for the user to press enter). You can then wait for the other thread to release the mutex, then move the cursor and echo the character the user pressed at the appropriate part of the screen.
You can change the input mode using tcsetattr, although this is from termios which is for *nix systems. Since you're using windows, this may not work for you unless you're using cygwin.
maybe check this out: What is the Windows equivalent to the capabilities defined in sys/select.h and termios.h