Triggering Events on Input

Started by
0 comments, last by Zipster 21 years, 2 months ago
I''m having a little trouble with the triggering system I wrote. It''s main goal is to intercept user input into the stream buffer and trigger events on this input, all before anything is actually extracted. This happens in the underflow function, which I have overloaded in a class derived from basic_filebuf. Now, the only way the application gets input from the user is via the extraction operator. What''s important is that the extraction operator essentially attempts to get input from the user twice if it needs to, first when the sentry is constructed, and again when it uses get to get the data from the buffer. Since the sentry construction should get the user input, the second time it checks should pass because there is already data in the buffer, and the user isn''t queried again. Here''s my dilemma. One of my event types which justs prints special output to the screen has a "Press return key to continue.." prompt, which allows the user to pause for a moment and read what''s being printed. In order for this pause to work, I have to use cin.get() to wait for the return key. However, if the input that triggered the event is still in the buffer, then cin.get() will grab that, instead of waiting for a new return. In addition, it will also interpret the trigger as real input, and that''s a problem (see below). Now remember that the extraction operator checks the buffer twice, and the first check is where the user usually enters something. If I flush the buffer before calling cin.get(), then the return will work. However, if the buffer is cleared in the first check, then the second check will attempt to get user input again. This is fine and dandy behavior (exactly what I want), but only if the user enters something other than a trigger. If a trigger is entered again, the user will still get the prompt, and the code will still wait for the input, but since this is the second check, the code will interpret the last return key as raw input, and will try to convert it. This will trigger the application to display "Bad Input" because it isn''t a valid integer, float, character, etc., when in reality it shouldn''t be considered as input, because it''s a special trigger. My question concerns how to resolve this. I can''t overload ipfx or any of the extraction operators, because I''m trying to stick with the standard input stream and only overload my special stream buffer. I can''t remove the buffer flush, because I can''t have the stream interpret the special trigger as input. The easiest solution would be to not flush the buffer, however I can''t have the stream interpreting the special trigger as input. Then it will spit out error messages to the user saying that they have entered invalid input (cin fails, in other words), when it''s really just "special input," not invalid. Flushing the buffer only delays this behavior, and doesn''t eliminate it. To sum things up, the behavior I want is such: program uses extraction operator to get input from the user, user enters a trigger, output is displayed, program waits for return key, program waits again for new input. The program shouldn''t even attempt to convert the special trigger into anything, because it isn''t conventional input. If another trigger is entered, this process repeats. Otherwise, input is extracted normally and program continues. The entire thing works, except for this small detail.
Advertisement
I have doubts as to whether the stream buffer is the right place to do such things. Writing your own stream object and plugging cin's buffer into it would probably be better. As you remarked yourself, that's where the hooks are made available.

However, here's a hack :

Have your stream buffer check a flag to decide whether it should do trigger processing or not. If you place that flag in the stream buffer, then the encapsulating stream object will not know how to set it (as it is not part of the basic_streambuf interface). Conversely, your usual stream buffer doesn't know about what stream object(s) is controlling it.

If you're willing to give your stream buffer knowledge of what single stream it is plugged into (storing a pointer to it), then you can make use of the extension flag hooks (xalloc/iword/pword) available for stream objects (watch out for memory leaks if pword points to dynamically allocated memory : use a stream callback to cleanup).

* construct your stream buffer.
* call a 'binding' function that
*** sets the stream buffer in the stream object
*** sets the stream back pointer in the stream buffer
*** xalloc() room for the 'check trigger' flag (iword) in the stream object
*** initialise the flag as appropriate
*** return the original stream buffer of the stream object (as usual)
* use custom stream manipulators ( of the same breed as endl or width ) to set/clear the 'check trigger' flag in the stream as required
* have underflow check that flag through the back pointer to decide whether to check for a trigger or not.
* bend over and accept the performance hit

EDIT: remember to overload xsgetn() so that it only checks for triggers once.

[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

[edited by - Fruny on February 12, 2003 1:54:51 PM]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan

This topic is closed to new replies.

Advertisement