Asynchronous console input in C++

 
Post new topic   Reply to topic    mudlab.org Forum Index -> Coding
View previous topic :: View next topic  
Author Message
Grabnar



Joined: 30 Apr 2006
Posts: 15

PostPosted: Mon Aug 21, 2006 11:25 pm    Post subject: Asynchronous console input in C++ Reply with quote

I've been coding a small text application for a while now, and so far I've used the typical C console functions for getting user input, ie cin, cin.getline, getchar, etc.

The problem I have now is that all those commands seem to halt the program indefinitely until the user provides input. Which is fine for a very static program, but I need to be able to do stuff (like calculate outcomes and display those outcomes) while the user is typing in his or her response, real time.

Basically, I want to be able to listen for console input every now and then, and if there isn't any input, I want the program to chug along and do its own thing until it is once again time to listen for input.

None of the typical C console functions I've looked at so far allow for this; they all have to halt the flow of the program completely until the user decides to press a key.

Is there a way to do this that's fairly platform-generic (ie not using system calls or assembly language code to read the keyboard buffer)? Any help would be greatly appreciated.
Back to top
View user's profile Send private message
Author Message
Grabnar



Joined: 30 Apr 2006
Posts: 15

PostPosted: Tue Aug 22, 2006 4:33 am    Post subject: Reply with quote

Nevermind, I think I figured it out Embarassed
Back to top
View user's profile Send private message
Author Message
Kaz



Joined: 05 Jun 2005
Posts: 24
Location: Hampshire, UK

PostPosted: Thu Aug 24, 2006 2:17 pm    Post subject: Reply with quote

There is no platform-independent way of implementing asynchronous user input from the console. You'll have to resort to platform-specific calls.
Back to top
View user's profile Send private message
Author Message
Lindahl



Joined: 29 May 2005
Posts: 56

PostPosted: Mon Aug 28, 2006 9:46 pm    Post subject: Reply with quote

The most general way to do this in a POSIX (most unices) environment would be to set the file descriptor to non-blocking, using fcntl (see the man pages for exact syntax). If there's no input to be read, the 'read' call returns immediately with an error of EAGAIN.

For Windows it's just as esoteric, using the WaitForSingleObject on a HANDLE returned from GetStdHandle(STD_INPUT_HANDLE) with a timeout of zero (again, I'm not certain of the exact syntax).

Both of these are well documented on the internet, so do some searching. Note that you're working with raw bytes and system calls here, not the typical entry-level c/c++ constructs (i.e. cin >> input). Wrapping this in some platform-independent interface would be a good way to start. Once you have an interface you like, then implement the details. Keep in mind that you'll need to create an interface that can conform to both methods of asynchronous input.
Back to top
View user's profile Send private message
Author Message
Kelson



Joined: 18 May 2005
Posts: 71
Location: SC

PostPosted: Fri Sep 15, 2006 11:43 am    Post subject: Reply with quote

A multi-threaded application can handle the problem and be relatively platform-independent (or rather, simple to code the differences for each platform), but would require the program be designed to update based on input instead of relying on it to drive the world. My mud does this for example - all input are handled as events (both for remote and local users). The event handler updates the game engine executes the instructions when it gets to them (updates to the simulation, as it were).
Back to top
View user's profile Send private message Send e-mail AIM Address
Author Message
elanthis



Joined: 13 Apr 2006
Posts: 10

PostPosted: Sat Sep 16, 2006 12:20 am    Post subject: Reply with quote

Instead of doing threading (way overkill, and provides a huge assortment of problems that entry-level coders aren't equipped to handle properly) or using non-blocking descriptors (causes your program to loop and eat CPU usage even when doing nothing), the proper solution is to just use multi-plexing services.

You could code things using select() or poll(), or...

You could just use the BOOST multiplexing libraries.

If you are coding with C++, get familiar with BOOST. (http://www.boost.org) The project is driven by C++ language committee members and many parts of BOOST are used to design and develop new C++ features. In fact, one can be almost certain that platform independent network IO and multiplexing will be a part of the next C++ standard library TR2, and will be based on the BOOST libraries. Almost all of the additions in TR1 were BOOST contributions, too.
Back to top
View user's profile Send private message
Author Message
Tyche



Joined: 13 May 2005
Posts: 176
Location: Ohio, USA

PostPosted: Sat Sep 16, 2006 2:54 am    Post subject: Reply with quote

elanthis wrote:

You could just use the BOOST multiplexing libraries.


What Boost multiplexing libraries? I couldn't find any, just a proposal.

You realize he was asking about platform independent console I/O right?
Back to top
View user's profile Send private message Visit poster's website
Author Message
elanthis



Joined: 13 Apr 2006
Posts: 10

PostPosted: Sat Sep 16, 2006 5:04 pm    Post subject: Reply with quote

D'oh. I've spent the last few days reading through library proposals and C++ working group papers and members' proposals, I must've mixed myself up.

Granted, assuming that one of the proposed libraries becomes official (either in BOOST or the C++ standard library), it would handle console I/O as well as network I/O, I imagine. Smile

Instead of BOOST, one could also look at the ACE library (http://www.cs.wustl.edu/~schmidt/ACE-overview.html), but that isn't something I've used myself and I can't offer any concrete recommendations for it.
Back to top
View user's profile Send private message
Author Message
Tyche



Joined: 13 May 2005
Posts: 176
Location: Ohio, USA

PostPosted: Sat Sep 16, 2006 10:32 pm    Post subject: Reply with quote

elanthis wrote:
Instead of BOOST, one could also look at the ACE library (http://www.cs.wustl.edu/~schmidt/ACE-overview.html), but that isn't something I've used myself and I can't offer any concrete recommendations for it.


I modeled TeensyMUD's networking on Schmidt's Reactor/Acceptor/Connector patterns. I also did a C++ server earlier (without Connector). Code can be found here:
http://sourcery.dyndns.org/svn/mesh/trunk/mesh/network/networkservice/

BTW, the way Lindahl mentioned is how it's usually done on Windows versus select on *nix. But one thing not mentioned is that interpreting the keycode values from console input is not only platform dependent but terminal dependent. Windows has it's own way and can return one or two bytes for each key.

I think that curses (windows pdcurses) is probably the best way to go if one wants to write a console application that's mostly platform neutral. Of course hardly anyone is writing console apps these days. Even those playing with IF have gone GUI. Razz
Back to top
View user's profile Send private message Visit poster's website
Author Message
Shadus



Joined: 01 Sep 2007
Posts: 8

PostPosted: Sun Sep 02, 2007 10:32 am    Post subject: Consider Abstraction Reply with quote

Learning boost is good and such, but abstract it. That's what C++ is there for. Don't be afraid of using abstraction when you need it, just design an inheritance class, some precompiler #if WINDOWS #endif, etc, and let the abstracted class know what platform you're on. You should only need to do this in very critical areas since, even though the commands may be syntactically different, the result are usually the same.
This also doesn't require the learning of BOOST (which could be a recommendation anyways) or any other library, and would be good for learning why multi-environment coding sucks. Every platform has skeletons in their closet... except SCO. SCO is perfect and almighty.

But this is probably beyond the scope of your question.

PS: Don't fall for multi-threading. Even Admiral Ackbar said it's a trap. Use it only when you have something that forces a block onto you (which is mostly just r_gethost or whatever its called, something like that) for servers. There's no reason you should HAVE to HAVE threads for asynchronous I/O.
Back to top
View user's profile Send private message AIM Address MSN Messenger
Display posts from previous:   
Post new topic   Reply to topic    mudlab.org Forum Index -> Coding All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2001, 2002 phpBB Group
BBTech Template by © 2003-04 MDesign