C++ FLTK's Fl_Input data with update/validate loop - c++

FLTK is a callback based GUI system but there are times that I need a user to input an acceptable answer into a Fl_Input widget before a function can return.
This seems to require updating the widget, collecting the answer then returning the answer if it is valid.
So, in essence let's say I have a function called int get_int(Fl_Input i). This function needs to continually update the Fl_Input, validate the contents by attempting to cast the value() to an int, clear Fl_Input if the validation fails, and finally return the cast int from the function. This validation should happen on the press of enter key. (I plan to also have functions to return cast strings and floats but they'll work the same way)
This is actually part of a scripting system and FLTK is the GUI. The embedded language is waiting to get a proper int from my Fl_Input but FLTK can't update and process events because it has not completed the main loop. I can't easily do this via normal FLTK callbacks it seems because they must return void and I'll have many types of casting and validation on my single input depending on the context of the object reading from it.
Thanks to anyone who can help me!
EDIT here is some rough example code of what I need.
Embeddable Common Lisp needs to wrap the get_int function but I'm not sure how to update all widgets with an interrupt and also break the loop with a callback which can't affect the loop directly. (boolean flag maybe?)
#include <iostream>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <Fl/Fl_Input.H>
#include <Fl/Fl_Button.H>
#include <stdexcept>
int get_int(Fl_Input* i)
{
int temp = 0;
while(True)
{
// not sure how to update here
// at this point, button and field need to update
// also somehow validate needs to be done on Enter button press
// but callbacks can't interact with this part of the code directly
// to validate and end the loop here
try
{
temp = std::stoi(i->value());
}
catch(...)
{
std::cout << "Invalid conversion to int" << i->value() << std::endl;
i->value("");
}
}
return temp;
}
void field_callback(Fl_Widget * w, void *d)
{
// This callback simulates Embeddable Common Lisp calling wrapped get_int
// Once a number is valid, it is converted and passed to back to Lisp
int something = get_int((Fl_Input*)w);
std::cout << something << std::endl;
}
int main()
{
Fl_Window *w = new Fl_Window(200, 32);
Fl_Input *i = new Fl_Input(0, 0, 128, 24, "");
Fl_Button *b = new Fl_Button(128, 0, 32, 24, "Simulate Request");
b->callback(field_callback);
w->show();
return(Fl::run());
}

Well after some help on FLTK's mailing list I've composed an example for those looking to do a similar thing. This was just off the cuff and might be buggy for production use. Be sure to debug and not copy/paste directly.
#include <FL/Fl.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>
#include <string>
#include <iostream>
Fl_Window* win = new Fl_Window(240, 128, "Loop n Prompt");
Fl_Button* button = new Fl_Button(5, 5, 128, 24, "Simulate Prompt");
Fl_Input* input = new Fl_Input(5, 96, 230, 24, "");
Fl_Box* prompt_msg = new Fl_Box(5, 48, 230, 24, "");
std::string get_input(const char* prompt, Fl_Input *input)
{
// Lock all widgets not pertaining to field here
button->deactivate();
prompt_msg->label(prompt);
// Open up the input for value entry
input->readonly(false);
input->activate();
while(! input->readonly())
{
Fl::wait();
}
// other groups activate here
button->activate();
// Have a funny feeling about c -> std::string conversion double check...
std::string return_string = input->value();
// Reset input and prompt to ""
input->value("");
prompt_msg->label("");
return return_string;
}
void input_CB(Fl_Widget *w, void* data)
{
Fl_Input* ptr = (Fl_Input*)w;
ptr->readonly(true);
}
void button_CB(Fl_Widget *w, void* data)
{
// Simulate something needing these values RIGHT NOW
std::cout << "Got " << get_input("Please enter name", input) << std::endl;
std::cout << "Got " << get_input("Please enter mother's name", input) << std::endl;
std::cout << "Got " << get_input("Please enter father's name", input) << std::endl;
// Now try a standard loop until thing
std::string password = "";
while(password != "password")
{
password = get_input("You must enter 'password'", input);
}
std::cout << "Nice job you answered correctly to exit the loop!" << std::endl;
}
int main()
{
// Callback setup
input->callback((Fl_Callback*)input_CB);
button->callback((Fl_Callback*)button_CB);
// Entry field does callback when enter key pressed
input->when(FL_WHEN_ENTER_KEY_ALWAYS);
// Show the window and all children
win->show();
return(Fl::run());
}

Related

How do I redirect stderr to /dev/null in C++?

#include <cstddef>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
//read the lines from the piped file using cin
string response;
int i = 0;
while (getline(cin, response)) {
//if the response is empty, stop
if (response.empty()) {
break;
}
//Write each odd line (1,3, etc..) to stderr (cerr)
//Write each even line (2,4. etc..) to stdout (cout)
if (i % 2 != 1) { //send odd to stderr
cerr << "err: " << response << endl;
}
else { //send even to stdout
cout << "out: " << response << endl;
}
i++;
}
return 0;
}
I want to redirect stderr to /dev/null, how would I go about doing so? I'm new to C++ and trying to learn by practicing, however, I'm not easily able to find an answer that fits my existing program.
Besides the excellent commentary above, it is pretty easy to make a “null” streambuf sink in C++.
#include <iostream>
struct null_streambuf: public std::streambuf
{
using int_type = std::streambuf::int_type;
using traits = std::streambuf::traits_type;
virtual int_type overflow( int_type value ) override
{
return value;
}
};
To use it, just set the rdbuf:
int main()
{
std::cerr.rdbuf( new null_streambuf );
std::cerr << "Does not print!\n";
}
If you wish to be able to turn it off and on, you will have to remember the original and restore it, not forgetting to delete the new null_streambuf.
int main()
{
std::cerr << "Prints!\n";
auto original_cerr_streambuf = std::cerr.rdbuf( new null_streambuf );
std::cerr << "Does not print.\n";
delete std::cerr.rdbuf( original_cerr_streambuf );
std::cerr << "Prints again!\n";
}
This does have the objective effect of being compiled to code, which I suspect is the advantage you are looking for: the ability to dynamically enable and disable diagnostic output.
This is, however, the usual function of a debug build, where you use the DEBUG macro to decide whether or not to compile something (such as error output operations) into the final executable.
Keep in mind that this does not disable output on standard error via other means, but only through cerr.

Function to interrupt the loop by any pressed key

I'm new to C++. Have decided to do my own game. And i want to make a starting screen for it. And the problem is that i havent found the way to make an "Press any key to continue" function while dots continue. I made the loop for the programm to wait till any would be pressed but dots dont want to display in.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <windows.h>
using namespace std;
int pressCheck(){
char c = 0;
c = getchar();
if (c == 0)
return 1;
return 0;
}
int main()
{
cout << "\t\t\t\t Hello" << endl;
Sleep(300);
cout << "\t\t Welcome to my new game BITHCES!" << endl << endl;
Sleep(700);
cout << "\t\t\tPress any key to proceed";
while(!pressCheck()){
Sleep(300);
cout << ".";
Sleep(300);
cout << ".";
Sleep(300);
cout << ".";
}
getchar();
system("cls");
Sleep(100);
return 0;
}
If you are creating a text based game I would recommend using ncurses (or pdcurses for windows):
[...] a toolkit for developing "GUI-like" application software that runs
under a terminal emulator.
Implementing what you have above would be something like
#include <string>
#include <ncurses.h> // This header might be different on windows
#include <unistd.h> // for usleep, replace with Windows.h (?)
void DisplayCentre(int yy, const std::string& str)
{
// Get the screen size
int y, x;
getmaxyx(stdscr, y, x);
// Compute starting location for string (centre)
x = (x - str.size())/2;
// Write the string to the window
mvwprintw(stdscr, yy, x, str.c_str());
// Make sure the screen is updated
refresh();
}
void PromptForKey(void)
{
// Get the screen size
int y, x;
getmaxyx(stdscr, y, x);
// Write a message at the bottom left of the screen
mvwprintw(stdscr, y-1, 0, "Press any key to continue");
// Set a time-out for wgetch
wtimeout(stdscr, 300);
// While the user hasn't entered a character
while (wgetch(stdscr) == ERR)
{
// Add another dot to the screen
waddch(stdscr, '.');
refresh();
}
// Clear time-out
notimeout(stdscr, true);
}
int main(int argc, char** argv)
{
initscr(); // Initialize curses
cbreak(); // Make typed characters immediately available
noecho(); // Don't automatically print typed characters
curs_set(0); // Make the cursor invisible (where supported)
// Display `Hello' (at line 10)
DisplayCentre(10, "Hello");
// Delay (you might want to use Sleep())
sleep(1);
// Display `Welcome to my new game' (at line 15)
DisplayCentre(15, "Welcome to my new game");
sleep(1);
// Prompt user for key
PromptForKey();
// Close down curses
endwin();
return 0;
}
To compile this program on Linux I use g++ test.cpp -lncurses. On windows you will probaly need to replace sleep with the windows Sleep function and use the appropriate header. You may also need to use an alternative to ncurses.
However, if you are just learning to program I would suggest you try using ncurses in Python. Python has the benefit of being an interpreted language so you don't need to worry too much about compiling or linking executables. Python is also mostly cross platform. The above implemented in Python:
#!/usr/bin/python
from curses import *
from time import sleep
def promptForKey(win):
""" Ask the user to press any key to continue. """
# Get screen size
y,x = win.getmaxyx()
# Display prompt
win.addstr(y-1, 0, "Press any key to continue")
win.refresh()
# Set time-out
win.timeout(300)
while (win.getch() == ERR):
win.addch('.')
# Disable time-out
win.notimeout(True)
def dispCentre(win, yy, string, delay):
""" Display string at line yy and wait for delay milliseconds. """
# Get screen size
y,x = win.getmaxyx()
# Display string in centre
x = (x - len(string))/2
win.addstr(yy, x, string)
win.refresh()
# Delay
sleep(delay)
if __name__ == '__main__':
# Initialize curses
win = initscr()
cbreak()
noecho()
curs_set(0)
# Display some stuff
dispCentre(win, 10, "Hello", 0.3)
dispCentre(win, 15, "Welcome to my new game", 0.7)
promptForKey(win)
# Close down curses
endwin()
i know i am late but i think maybe you wanted to do this? (Run the attached code)
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <windows.h>
#include<conio.h>
using namespace std;
bool pressCheck(){
if (getch())
return 1;
return 0;
}
int main()
{
cout << "\t\t\t\t Hello" << endl;
Sleep(300);
cout << "\t\t Welcome to my new game BITHCES!" << endl << endl;
Sleep(700);
cout << "\t\t\tPress any key to proceed";
while(!pressCheck()){
Sleep(300);
cout << ".";
Sleep(300);
cout << ".";
Sleep(300);
cout << ".";
}
system("cls");
Sleep(100);
return 0;
}

Doing multiple jobs at the same time in C++

I have made a login Command Line interface in C++ where a marquee will run for indefinite time and in the next line a user can enter his id and password. I want both these work i.e. marquee and id input at the same time but with the below code only marquee is running for infinite time. I am using windows OS and i am new to C++ so I am not able to apply thread concepts.
char m[]={"- A cool marquee effect. Programmed by Roneet -"};
int main()
{
marquee();
cout<<setw(35)<<"Enter Username : ";
getline(cin,str);
cout<<setw(35)<<"Enter Password : ";
return 0;
}
void marquee()
{
while(a<131)
{
p=m[0];
m[0]=m[c];
m[c]=p;
for(j=1;j<=b;j++)
cout<<m[j];
for(j=0;j<N;j++){}
c--;
cout<<"\r";
if(c<1){c=b;a++;if(a==100)N=51500;}
}
system("PAUSE");
}
First of all, std streams are not thread safe, you need to add std::mutex to protect each std::cout operation.
Secondly, to easily execute a function in a separate thread, use std::async
#include <future>
std::future<void> fut = std::async(&marquee);
Example:
#include <atomic>
#include <future>
#include <string>
#include <iostream>
std::atomic<bool> cond{ false };
void marquee()
{
while (!cond)
{
std::cout << '*' << std::flush;
}
}
int main()
{
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cerr.tie(nullptr);
std::cout << "Enter username and then password: " << std::flush;
std::future<void> task = std::async(std::launch::async, &marquee);
std::string user, pass;
std::cin >> user >> pass;
cond = true;
task.get();
return 0;
}

How can you update the gtkmm gui screen from your c++ code after it is created

Can someone help to clear up the confusion of how to update a gui window without user input.
In other words, I would like to be able to output text to either or both the console our the gui window.
At present I can call the gui window (Window with a label for example) and output the initial text. However, the process doesn't return to my c++ code until the window closes. I'm trying to figure out how to (or where to have my code) for updating the gui screen before the gui window exits.
This is an example:
#include <gtkmm.h>
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
Gtk::Main kit(argc, argv);
Gtk::Window window;
Gtk::TextView textview;
Gtk::Label label;
string mylabeltext = "This is the first line of text in my gui window.\n";
window.set_default_size(600, 360);
window.set_title("Gtkmm Programming - C++");
window.set_position(Gtk::WIN_POS_CENTER);
label.show();
window.add(label);
label.set_text(mylabeltext);
mylabeltext += "About to run some routines...\n";
label.set_text(mylabeltext);
cout << "An initial line has been set to the gui window." << endl;
// The Gui Window is displayed
Gtk::Main::run(window);
// Now my main program has performed some functions and wants to update
// the console and the gui window.
cout << "Continuing after various functions and processing..." << endl;
mylabeltext = "Showing the results of the functions and processing.";
label.set_text(mylabeltext);
return 0;
}
The last line of text is never printed to the console until the gui is exited. The last line of the mylabeltext is never printed to the label window.
What I'm trying to describe is how to keep the gtkmm window active while I run other routines in my c++ code and update the output to both the console and the gui window without closing the gui window to continue the c++ routines.
All the examples that I can find uses a button in the code. I have tested and experimented enough that I can update the gui screen after a button is pressed. However, I don't want to have to rely on the user for screen updates. I hope to be able to run disc scans and other functions and periodically update the screen so that the user can see the progress and know that the program is still working and not dead.
Some of the resources that I have studied in my attempts at understanding this include:
https://developer.gnome.org/
https://developer.gnome.org/gtkmm-tutorial/3.2/gtkmm-tutorial.html
http://en.wikipedia.org/wiki/Gtkmm
Like tp1 said in their comment on your question, a timer is going to be the easiest way to do this.
To set a 1.5 second timeout that will call another function, do this (gtkmm 3):
#include <gtkmm.h>
#include <iostream>
using namespace std;
class MyApp : public Gtk::Window{
public:
Gtk::Label label;
bool on_timeout(); //return true to keep the timeout and false to end it
MyApp();
virtual ~MyApp();
};
MyApp::MyApp(){
string mylabeltext = "This is the first line of text in my gui window.\n";
set_default_size(600, 360);
set_title("Gtkmm Programming - C++");
set_position(Gtk::WIN_POS_CENTER);
add(label);
label.set_text(mylabeltext);
mylabeltext += "About to run some routines...\n";
label.set_text(mylabeltext);
cout << "An initial line has been set to the gui window." << endl;
//create slot for timeout signal
int timeout_value = 1500; //in ms (1.5 sec)
sigc::slot<bool>my_slot = sigc::mem_fun(*this, &MyApp::on_timeout);
//connect slot to signal
Glib::signal_timeout().connect(my_slot, timeout_value);
show_all_children();
}
MyApp::~MyApp(){
}
bool MyApp::on_timeout(){
cout << "Continuing after various functions and processing..." << endl;
string temp = label.get_text();
temp += "Showing the results of the functions and processing.\n";
label.set_text(temp);
return true;
}
int main(int argc, char* argv[])
{
Glib::RefPtr<Gtk::Application> app = Gtk::Application::create(argc, argv, "com.kaze.test");
MyApp myapp;
// The Gui Window is displayed
return app->run(myapp);
}
More info here: https://developer.gnome.org/gtkmm-tutorial/3.3/sec-timeouts.html.en
This is crude, but this is functional for what I was trying to do:
#include <gtkmm.h>
#include <iostream>
using namespace std;
class myLabel: public Gtk::Window
{
public:
myLabel();
virtual ~myLabel();
protected:
Gtk::Label m_label;
string labeltext;
string newtext;
void myprocess1();
};
myLabel::myLabel() :
m_label()
{
void myprocess1();
set_title("Gtkmm Programming - C++");
add(m_label);
m_label.show();
Glib::Thread::create(sigc::mem_fun(*this, &myLabel::myprocess1), true);
}
myLabel::~myLabel()
{
}
void myLabel::myprocess1()
{
labeltext = "About to preform a number of processes.\n";
labeltext += "Each process may take up to three hours.\n";
labeltext += "Please carry your daily chores and wait.\n";
cout << labeltext;
cout.flush();
m_label.set_text(labeltext);
sleep(10); // Back from a three hour function
newtext = "Back from a three hour function\n";
labeltext += newtext;
m_label.set_text(labeltext);
cout << newtext;
cout.flush();
sleep(10); // Back from a three hour function
newtext = "Back from another three hour function\n";
labeltext += newtext;
m_label.set_text(labeltext);
cout << newtext;
cout.flush();
newtext = "Exiting in 1 minute...\n";
labeltext += newtext;
m_label.set_text(labeltext);
cout << newtext;
cout.flush();
sleep(60);
exit(0);
}
int main(int argc, char* argv[])
{
if (Glib::thread_supported())
Glib::thread_init();
else
{
cerr << "Threads aren't supported!" << endl;
exit(1);
}
Gtk::Main kit(argc, argv);
myLabel mylabel;
Gtk::Main::run(mylabel);
return 0;
}
Hope the example can help anyone else that wants to output to the gtkmm gui with updates, similar to updating info to the console.

Non-blocking console input C++

I'm looking for a (multiplatform) way to do non-blocking console input for my C++ program, so I can handle user commands while the program continually runs. The program will also be outputting information at the same time.
What's the best/easiest way to do this? I have no problem using external libraries like boost, as long as they use a permissive license.
Example using C++11:
#include <iostream>
#include <future>
#include <thread>
#include <chrono>
static std::string getAnswer()
{
std::string answer;
std::cin >> answer;
return answer;
}
int main()
{
std::chrono::seconds timeout(5);
std::cout << "Do you even lift?" << std::endl << std::flush;
std::string answer = "maybe"; //default to maybe
std::future<std::string> future = std::async(getAnswer);
if (future.wait_for(timeout) == std::future_status::ready)
answer = future.get();
std::cout << "the answer was: " << answer << std::endl;
exit(0);
}
online compiler: https://rextester.com/GLAZ31262
I would do this by creating separate a thread which calls normal blocking IO functions and pass it a callback function which it would call when it got input. Are you sure you need to do what you said you want to do?
As for outputting information at the same time, what would happen if the user was in the middle of typing some input and you printed something?
I've done this on QNX4.5 that doesn't support threads or Boost by using select. You basically pass select STDIN as the file descriptor to use and select will return when a new line is entered. I've added a simplified example loop below. It's platform independent, at least for Unix like systems. Not sure about Windows though.
while (!g_quit)
{
//we want to receive data from stdin so add these file
//descriptors to the file descriptor set. These also have to be reset
//within the loop since select modifies the sets.
FD_ZERO(&read_fds);
FD_SET(STDIN_FILENO, &read_fds);
result = select(sfd + 1, &read_fds, NULL, NULL, NULL);
if (result == -1 && errno != EINTR)
{
cerr << "Error in select: " << strerror(errno) << "\n";
break;
}
else if (result == -1 && errno == EINTR)
{
//we've received and interrupt - handle this
....
}
else
{
if (FD_ISSET(STDIN_FILENO, &read_fds))
{
process_cmd(sfd);
}
}
}
There is one easy way:
char buffer[512];
int point = 0;
...
while (_kbhit()) {
char cur = _getch();
if (point > 511) point = 511;
std::cout << cur;
if (cur != 13) buffer[point++] = cur;
else{
buffer[point] = '\0';
point = 0;
//Run(buffer);
}
}
No block, all in 1 thread. As for me, this works.
Non-blocking console input C++ ?
Ans: do console IO on a background thread and provide a means of communicating between threads.
Here's a complete (but simplistic) test program that implements async io by deferring the io to a background thread.
the program will wait for you to enter strings (terminate with newline) on the console and then perform a 10-second operation with that string.
you can enter another string while the operation is in progress.
enter 'quit' to get the program to stop on the next cycle.
#include <iostream>
#include <memory>
#include <string>
#include <future>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>
int main()
{
std::mutex m;
std::condition_variable cv;
std::string new_string;
bool error = false;
auto io_thread = std::thread([&]{
std::string s;
while(!error && std::getline(std::cin, s, '\n'))
{
auto lock = std::unique_lock<std::mutex>(m);
new_string = std::move(s);
if (new_string == "quit") {
error = true;
}
lock.unlock();
cv.notify_all();
}
auto lock = std::unique_lock<std::mutex>(m);
error = true;
lock.unlock();
cv.notify_all();
});
auto current_string = std::string();
for ( ;; )
{
auto lock = std::unique_lock<std::mutex>(m);
cv.wait(lock, [&] { return error || (current_string != new_string); });
if (error)
{
break;
}
current_string = new_string;
lock.unlock();
// now use the string that arrived from our non-blocking stream
std::cout << "new string: " << current_string;
std::cout.flush();
for (int i = 0 ; i < 10 ; ++i) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << " " << i;
std::cout.flush();
}
std::cout << ". done. next?\n";
std::cout.flush();
}
io_thread.join();
return 0;
}
sample test run:
$ ./async.cpp
first
new string: first 0 1las 2t 3
4 5 6 7 8 9. done. next?
new string: last 0 1 2 3 4 5 6 7 8quit 9. done. next?
ncurses can be a good candidate.
The StdinDataIO class of the BSD-licensed MUSCLE networking library supports non-blocking reads from stdin under Windows, MacOS/X, and Linux/Unix ... you could use that (or just examine the code as an example of how it can be done) if you want.
You can use the tinycon library to do this. Just spawn a tinycon object in a new thread, and you are pretty much done. You can define the trigger method to fire off whatever you'd like when enter is pressed.
You can find it here:
https://sourceforge.net/projects/tinycon/
Also, the license is BSD, so it will be the most permissive for your needs.
libuv is a cross-platform C library for asynchronous I/O. It uses an event loop to do things like read from standard input without blocking the thread. libuv is what powers Node.JS and others.
In a sense, this answer is incomplete. But yet, I think it can be useful even for people who have different platforms or circumstances, giving the idea, what to look for in their platform.
As I just wrote some scripting engine integration into an SDL2 main event loop (which is supposed to read lines from stdin if there are lines to be read), here is how I did it (on linux (debian bullseye 64 bit)). See below.
But even if you are not on linux, but on some other posix system, you can use the equivalent platform APIs of your platform. For example, you can use kqueue on FreeBSD. Or you can consider using libevent for a bit more portable approach (still will not really work on Windows).
This approach might also work on Windows if you do some special fiddling with the rather new-ish ConPTY. In traditional windows console applications, the problem is, that stdin is not a real file handle and as such, passing it to libevent or using IOCP (IO completion ports) on it will not work as expected.
But, this approach should also work on posix systems, if there is redirection at play. As long as there is a file handle available.
So how does it work?
Use epoll_wait() to detect if there is data available on stdin. While consoles can be configured in all sorts of ways, typically, they operate on a line by line basis (should also apply for ssh etc.).
Use your favorite getline() function to read the line from stdin. Which will work, because you know, there is data and it will not block (unless your console is not defaulting to line by line handling).
Rince and repeat.
#include <unistd.h>
#include <sys/epoll.h>
#include <iostream>
#include <string>
#include <array>
using EpollEvent_t = struct epoll_event;
int main(int argc, const char* argv[]) {
//
// create epoll instance
//
int epollfd = epoll_create1(0);
if (epollfd < 0) {
std::cout << "epoll_create1(0) failed!" << std::endl;
return -1;
}
//
// associate stdin with epoll
//
EpollEvent_t ev;
ev.data.ptr = nullptr;
ev.data.fd = STDIN_FILENO; // from unistd.h
ev.data.u32 = UINT32_C(0);
ev.data.u64 = UINT64_C(0);
ev.events = EPOLLIN;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, STDIN_FILENO, &ev) < 0) {
std::cout
<< "epoll_ctl(epollfd, EPOLL_CTL_ADD, fdin, &ev) failed."
<< std::endl;
return -1;
}
//
// do non-blocking line processing in your free running
// main loop
//
std::array<EpollEvent_t,1> events;
bool running = true;
while (running) {
int waitret = epoll_wait(epollfd,
events.data(),
events.size(),
0); // 0 is the "timeout" we want
if (waitret < 0) {
std::cout << "epoll_wait() failed." << std::endl;
running = false;
}
if (0 < waitret) { // there is data on stdin!
std::string line;
std::getline(std::cin, line);
std::cout
<< "line read: [" << line << "]" << std::endl;
if (line == "quit")
running = false;
}
// ... Do what you usually do in your main loop ...
}
//
// cleanup of epoll etc.
//
close(epollfd);
return 0;
}
You could do:
#include <thread>
#include <chrono>
#include <string>
#include <iostream>
int main() {
std::cout << "Type exit to quit." << std::endl;
// initialize other std::thread handlers here
std::string input;
while (input != "exit") {
std::getline(std::cin, input);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
std::cout << "Cleaning up and quitting" << std::endl;
return 0;
};
A simple answer with thread/future and reading a single char at a time (you can replace getchar with cin as required)
Timeout is set to zero and a new future is created every time the previous call is completed.
Like cin, getchar requires that the user hits the RETURN key to end the function call.
#include <chrono>
#include <cstdio>
#include <future>
#include <iostream>
#include <thread>
static char get_usr_in()
{
return std::getchar();
}
int main()
{
std::chrono::seconds timeout(0);
std::future<char> future = std::async(std::launch::async, get_usr_in);
char ch = '!';
while(ch!='q') {
if(future.wait_for(timeout) == std::future_status::ready) {
ch = future.get();
if(ch!='q') {
future = std::async(std::launch::async, get_usr_in);
}
if(ch >= '!' && ch <'~')
std::cout << "ch:" << ch << std::endl;
}
std::cout << "." << std::endl;
}
exit(0);
}
Why not use promises?
#include <iostream>
#include <istream>
#include <thread>
#include <future>
#include <chrono>
void UIThread(std::chrono::duration<int> timeout) {
std::promise<bool> p;
std::thread uiWorker([&p]() {
bool running = true;
while(running) {
std::string input;
std::cin >> input;
if(input == "quit") {
p.set_value(true);
running = false;
}
}
});
auto future = p.get_future();
if (future.wait_for(timeout) != std::future_status::ready) {
std::cout << "UI thread timed out" << std::endl;
uiWorker.detach();
return;
}
uiWorker.join();
}
int main()
{
std::thread uiThread(UIThread, std::chrono::seconds(3));
std::cout << "Waiting for UI thread to complete" << std::endl;
uiThread.join();
}
online complier