Thank you both for the help. 17 May 2004
infamous41md's suggestion led me to searching about
termios. A web page (quoted below) helped with
the needed syntax. Result: a solution.
In the interest of closure and to assist other readers,
attached below is my working C++ test program (it
consists mostly of comments).
Thanks,
Mark
/*
The following 3 commands compile this on my system.
/bin/rm -f stdin_test.o stdin_test
g++ -c stdin_test.cc
g++ stdin_test.o -lcurses -o stdin_test
*/
// program accepts charaters one at a time from stdin
// without waiting for a newline (unbuffered)
// based on:
http://www.erlenstar.demon.co.uk/unix/faq_4.html
//
// Modify the values of vtime and vmin (at appoximately line 62, below)
// to try different modes. The current values are: vtime = 1 and vmin = 0
// which allows the main program to poll for characters. Using vtime=1
// intentionally slows the speed of the main loop, changing vtime to zero
// will greatly increase the speed of the main loop.
//
// On my system, the some keys are still intercepted:
// "F1" calls up the "Gnome Terminal manual"
// "F10" opens a menu
// "Print Screen" runs a screen capture program
// "Scroll Lock" is intercepted, unknown action.
// "Pause" is intercepted, unknown action.
// "Num Lock" toggles status light (but not received values)
// keypad "home", "End", "PgUp", and "PgDn" scroll the terminal
#include <iostream>
#include <termios.h>
using namespace std;
// ---------------------------------------------------------------------------
void set_keypress(termios& stored_settings) {
// change the terminal settings to return each character as it is typed
// (disables line-oriented buffering)
// returns the original settings in the argument structure
// obtain the current settings flags
tcgetattr(0, &stored_settings);
// copy existing setting flags
termios new_settings = stored_settings;
// modify flags
// first, disable canonical mode
// (canonical mode is the typical line-oriented input method)
new_settings.c_lflag &= (~ICANON);
new_settings.c_lflag &= (~ECHO); // don't echo the character
new_settings.c_lflag &= (~ISIG); // don't automatically handle control-C
// vtime and vmin setting interactions are complex
// both > 0
// Blocks until it has first new character, then tries to get a total
// of vmin characters, but never waits more than vtime between characters.
// Returns when have vmin characters or the wait for next character is
// too long.
// vtime = 0, vmin > 0
// Blocks until vmin characters received (or a signal is received)
// vtime > 0, vmin = 0
// If a character is ready within vtime, it is returned immediately.
// If no character is avalable within vtime, zero is returned.
// both = 0
// Documentation somewhat unclear, but apparently returns immediately
// with all available characters up to the limit of the number
// requested by a read(). Returns -1 if no characters are available.
new_settings.c_cc[VTIME] = 1; // timeout (tenths of a second)
new_settings.c_cc[VMIN] = 0; // minimum number of characters
// apply the new settings
tcsetattr(0, TCSANOW, &new_settings);
// note:
// The return value from tcsetattr() is not tested because its value
// reflects "success" if any PART of the attributes is changed, not
// when all the values are changed as requested (stupidity!).
// Since the content of the termios structure may differ with
// implementation, as may the various constants such as ICANON, I see
// no elegant way to check if the desired actions were completed
// successfully. Comparing byte-by-byte shows the current state is
// NOT EQUAL to the requested state, and yet it runs, so the changes
// were apparently made. Can not check for success/failure.
}
// ---------------------------------------------------------------------------
void reset_keypress(const termios& stored_settings) {
// applies the terminal settings supplied as the argument
tcsetattr(0, TCSANOW, &stored_settings);
}
// ---------------------------------------------------------------------------
int main() {
// save the previous settings while modifying the current settings
termios stored_settings;
set_keypress(stored_settings);
cout << "Press keys... exit with a control-C." << endl;
// loop to poll for characters
while (true) {
int val = getc(stdin);
cerr << " " << val << endl;
if (val == 3) {
cout << "Saw control-c, exiting." << endl;
// return to original settings
reset_keypress(stored_settings);
exit(0);
}
}
return 0;
}
// ---------------------------------------------------------------------------