istream function that inputs character w/out return

Hi I'm new. I hope I make an intelligent post.

I'm trying to create a more command in C++. The more command is like the Unix more command where you write:

more file.txt

file.txt is arbitrary I happen to be using a file named tomsawyer.txt (The book in a text file).

Anyway when you press enter ('\n') more should read through one line of text. If you press space (' ') more should read through a page of text. I created a constant called page length which is the integer 20. Therefore, space reads through 20 lines of text by iterating the infile.getLine (sentence, line_length) command 20 times (see code). The third option is the user enters the letter 'q' this quits more.

My problem is, "how do I take just one character from the user without forcing them to press enter." I use the command cin.get (x) to get just one character. This works well if they press the enter key; however, if they press space then they have to press enter in order for the istream to interpret the space as a space. Put another way the cin.get (x) function requires a delimiter in order to know the user has finished typing.

There has to be a better way. How odd would it be if the Unix more command was like this. You press space, because you want to scan through a page of text, but then you have to press enter to actually scan it. However, enter has a second function: enter is also used to scan through one line of text.

Thus, is there some function out there I can use that ask the user for a character and as soon as the character is pressed inputs that character into the char variable x.

Here is my code:

/*
* more.cpp
*
*
* Created by Matthew Dunson on 9/6/09.
* Copyright 2009 The Ohio State University. All rights reserved.
*
*/

#include <iostream>
#include <fstream>
#include <iostream>
#include <cstring>
using namespace std;


int main()
{
char x;
int page_length = 20;
string filename, key_pressed;
ifstream infile;
cout << "What is the name of the file? ";
cin >> filename;
infile.open(filename.c_str(), ios::in);
if (!infile.is_open ())
{
cerr << "Input file " << filename << " opening failed." << endl;
return 1;
}

cin.get (x); // this is where the problem is!!!!!!!


while (!(x == 'q') && !infile.eof ())
{
if (x == '\n')
{
int line_length = 80;
char sentence[line_length];
infile.getline (sentence, line_length);
cout << sentence;
}
else if (x == ' ')
{
int counter = 0;
while (counter < page_length)
{
int line_length = 80;
char sentence[line_length];
infile.getline (sentence, line_length);
cout << sentence;
counter++;
}
}


cin.get (x); // this to is a problem !!!!!


}
infile.close ();
return 0;
}


I was reading on this website about Basic Input/Output (http://www.cplusplus.com/doc/tutorial/basic_io/)
and I think they came closest to explaining the limitations of cin.

"cin can only process the input from the keyboard once the RETURN key has been pressed. Therefore, even if you request a single character, the extraction from cin will not process the input until the user presses RETURN after the character has been introduced."

This is what I'm trying to fight: "How can i request a single character (in C++) and process the input without requiring the user to press RETURN.

Thank you for listening to my question. This was my very first post.
Interesting. The getch function would work, but please don't use it. It's old, deprecated and compiler (and possibly platform) related.
Ncurses may have a function for that. There is also this 'boost' thing which seems to be able to do everything - you could look into that ( http://www.boost.org ).
Thank you,
I'll check that out.
http://www.cplusplus.com/forum/articles/7312/page1.html#msg33734

You could also use the Curses library (as chrisname suggested).

NCurses
http://www.gnu.org/software/ncurses/
(POSIX)

PDCurses
http://pdcurses.sourceforge.net/
(Win32)
Last edited on
Thankyou guys,
Your advice made me go on an internet scavenger hunt, but I finally found something to include in my program so that it could take care of this feature. I included this function (I didn't create it -- I copied and pasted it from the internet) that was created by using objects from 3 different classes: <termios.h>, <unistd.h> and <assert.h>. I feel kind of bad that I used someone else's code (since I don't learn as much); however, I'm glad to have this done. To be honest checking out ncurses and pdcurses was a little overwhelming. I'm not use to including classes that are not part of the Standard template library. Is there a tutorial on how to use those libraries or is it something you just have to pick up? I think when I read more on classes I may begin to understand how this all works. Thanks for your help.

Here is my code:

/*
* more.cpp
*
*
* Created by Matthew Dunson on 9/6/09.
* Copyright 2009 The Ohio State University. All rights reserved.
*
*/

#include <iostream>
#include <termios.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <cstring>
using namespace std;

int getch(void);

int main()
{
char x;
int page_length = 20;
string filename, key_pressed;
ifstream infile;
cout << "What is the name of the file? ";
cin >> filename;
infile.open(filename.c_str(), ios::in);
if (!infile.is_open ())
{
cerr << "Input file " << filename << " opening failed." << endl;
return 1;
}
x = getch ();
while (!(x == 'q') && !infile.eof ())
{
if (x == '\n')
{
int line_length = 150;
char sentence[line_length];
infile.getline (sentence, line_length);
cout << sentence << endl;
}
else if (x == ' ')
{
int counter = 0;
while (counter < page_length)
{
int line_length = 150;
char sentence[line_length];
infile.getline (sentence, line_length);
cout << sentence << endl;
counter++;
}
}
x = getch ();
}
infile.close ();
return 0;
}

int getch(void) {
int c=0;

struct termios org_opts, new_opts;
int res=0;
//----- store old settings -----------
res=tcgetattr(STDIN_FILENO, &org_opts);
assert(res==0);
//---- set new terminal parms --------
memcpy(&new_opts, &org_opts, sizeof(new_opts));
new_opts.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOKE | ICRNL);
tcsetattr(STDIN_FILENO, TCSANOW, &new_opts);
c=getchar();
//------ restore old settings ---------
res=tcsetattr(STDIN_FILENO, TCSANOW, &org_opts);
assert(res==0);
return(c);
}
Topic archived. No new replies allowed.