I have been trying to get getch to work in another program with no success. So I have made the most basic program I can using getch the way I want it to work in the main program.
I have researched the need for noecho, cbreak, initscr and nodelay, I have also tried using newscr() but to no success.
The problem I am having is that the chars aren't being printed to the screen till I hit "enter", when they should be put to the screen every loop. Why is this happening? Also the cursor doesn't return to the left of the screen at the new line. eg.
abc
def
ghi
I have looked for the answer but am stumped again...
#include <stdio.h>
#include <ncurses.h>
int main()
{
initscr();cbreak(); noecho();nodelay(stdscr,0);
char c ;
while((c=getch())!=EOF){
putchar(c);}
return 0;
}
You're not seeing the output because your stdout stream is line buffered.
Your program is getting the individual characters all right; but the output stream is buffering them.
Try fflush(stdout); or switching stdout to unbuffered mode with setbuf(stdout, NULL);.
The problem with disabling buffering is that it's inefficient for bulk data processing when the output isn't a terminal.
You can make it conditional on the standard output being a tty:
if (isatty(fileno(stdout))) /* #include <unistd.h> */
setbuf(stdout, NULL);
To return the cursor to the start of the line, you need to put out a carriage return \r. This is because curses' cbreak mode has disabled the ONLCR tty mode (on Output, when sending NL add CR).
If you unconditionally add \r, then it will appear in files when your output is redirected. So again you need some isatty hack.
A much better might be to learn how to use the tcgetattr and tcsetattr functions to precisely control specific tty parameters, if all you want is to do character-at-a-time input without echo, and not actually develop an interactive curses-based program.
Do you really want character-at-a-time input, or just to diable echo? It's easy to disable echo. Call tcgetattr to fill a struct termios with the current settings of file descriptor 0 (if it is a tty). Flip some flags to turn off echoing, then call tcsetattr to install the updated structure. When your program exits, be nice and put back the original one. Done.
Yes, ncurses is a good way to get character-by-character control.
And yes, you must call "initscr()" and "cbreak()".
SUGGESTIONS:
1) Compare your code with this ncurses "hello world":
#include <ncurses.h>
int main()
{
initscr(); /* Start curses mode */
printw("Hello World !!!"); /* Print Hello World */
refresh(); /* Print it on to the real screen */
getch(); /* Wait for user input */
endwin(); /* End curses mode */
return 0;
}
2) See what happens if you do a "refresh()" and/or remove the "noecho()".
3) This tutorial has lots of good info that might also help:
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/
Related
I have been trying to get getch to work in another program with no success. So I have made the most basic program I can using getch the way I want it to work in the main program.
I have researched the need for noecho, cbreak, initscr and nodelay, I have also tried using newscr() but to no success.
The problem I am having is that the chars aren't being printed to the screen till I hit "enter", when they should be put to the screen every loop. Why is this happening? Also the cursor doesn't return to the left of the screen at the new line. eg.
abc
def
ghi
I have looked for the answer but am stumped again...
#include <stdio.h>
#include <ncurses.h>
int main()
{
initscr();cbreak(); noecho();nodelay(stdscr,0);
char c ;
while((c=getch())!=EOF){
putchar(c);}
return 0;
}
You're not seeing the output because your stdout stream is line buffered.
Your program is getting the individual characters all right; but the output stream is buffering them.
Try fflush(stdout); or switching stdout to unbuffered mode with setbuf(stdout, NULL);.
The problem with disabling buffering is that it's inefficient for bulk data processing when the output isn't a terminal.
You can make it conditional on the standard output being a tty:
if (isatty(fileno(stdout))) /* #include <unistd.h> */
setbuf(stdout, NULL);
To return the cursor to the start of the line, you need to put out a carriage return \r. This is because curses' cbreak mode has disabled the ONLCR tty mode (on Output, when sending NL add CR).
If you unconditionally add \r, then it will appear in files when your output is redirected. So again you need some isatty hack.
A much better might be to learn how to use the tcgetattr and tcsetattr functions to precisely control specific tty parameters, if all you want is to do character-at-a-time input without echo, and not actually develop an interactive curses-based program.
Do you really want character-at-a-time input, or just to diable echo? It's easy to disable echo. Call tcgetattr to fill a struct termios with the current settings of file descriptor 0 (if it is a tty). Flip some flags to turn off echoing, then call tcsetattr to install the updated structure. When your program exits, be nice and put back the original one. Done.
Yes, ncurses is a good way to get character-by-character control.
And yes, you must call "initscr()" and "cbreak()".
SUGGESTIONS:
1) Compare your code with this ncurses "hello world":
#include <ncurses.h>
int main()
{
initscr(); /* Start curses mode */
printw("Hello World !!!"); /* Print Hello World */
refresh(); /* Print it on to the real screen */
getch(); /* Wait for user input */
endwin(); /* End curses mode */
return 0;
}
2) See what happens if you do a "refresh()" and/or remove the "noecho()".
3) This tutorial has lots of good info that might also help:
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/
I have been trying to get getch to work in another program with no success. So I have made the most basic program I can using getch the way I want it to work in the main program.
I have researched the need for noecho, cbreak, initscr and nodelay, I have also tried using newscr() but to no success.
The problem I am having is that the chars aren't being printed to the screen till I hit "enter", when they should be put to the screen every loop. Why is this happening? Also the cursor doesn't return to the left of the screen at the new line. eg.
abc
def
ghi
I have looked for the answer but am stumped again...
#include <stdio.h>
#include <ncurses.h>
int main()
{
initscr();cbreak(); noecho();nodelay(stdscr,0);
char c ;
while((c=getch())!=EOF){
putchar(c);}
return 0;
}
You're not seeing the output because your stdout stream is line buffered.
Your program is getting the individual characters all right; but the output stream is buffering them.
Try fflush(stdout); or switching stdout to unbuffered mode with setbuf(stdout, NULL);.
The problem with disabling buffering is that it's inefficient for bulk data processing when the output isn't a terminal.
You can make it conditional on the standard output being a tty:
if (isatty(fileno(stdout))) /* #include <unistd.h> */
setbuf(stdout, NULL);
To return the cursor to the start of the line, you need to put out a carriage return \r. This is because curses' cbreak mode has disabled the ONLCR tty mode (on Output, when sending NL add CR).
If you unconditionally add \r, then it will appear in files when your output is redirected. So again you need some isatty hack.
A much better might be to learn how to use the tcgetattr and tcsetattr functions to precisely control specific tty parameters, if all you want is to do character-at-a-time input without echo, and not actually develop an interactive curses-based program.
Do you really want character-at-a-time input, or just to diable echo? It's easy to disable echo. Call tcgetattr to fill a struct termios with the current settings of file descriptor 0 (if it is a tty). Flip some flags to turn off echoing, then call tcsetattr to install the updated structure. When your program exits, be nice and put back the original one. Done.
Yes, ncurses is a good way to get character-by-character control.
And yes, you must call "initscr()" and "cbreak()".
SUGGESTIONS:
1) Compare your code with this ncurses "hello world":
#include <ncurses.h>
int main()
{
initscr(); /* Start curses mode */
printw("Hello World !!!"); /* Print Hello World */
refresh(); /* Print it on to the real screen */
getch(); /* Wait for user input */
endwin(); /* End curses mode */
return 0;
}
2) See what happens if you do a "refresh()" and/or remove the "noecho()".
3) This tutorial has lots of good info that might also help:
http://tldp.org/HOWTO/NCURSES-Programming-HOWTO/
I am creating a Linux terminal program using C.
I am trying to make a two digit code address a array location.
I don't want to have to hit enter after every two digit input, I want the input to just be sent to my buffer variable through scanf directly after to characters are entered.
I do not have a code sample, as i have no idea how to approach this.
Thanks for any help!
You've got two options, which solve the same problem in nearly the same way. The first is to use stdbuf when you run your program; the invocation is:
stdbuf -i0 ./a.out
Using that prevents stdin from being line-buffered, and will let you use fread() or similar commands to retrieve input as it happens.
The other is to put the terminal in raw mode. It's well-described here. But the downside is that control characters are no longer dealt with. In your program, you
#include <termios.h>
main(){
struct termios trm;
tcgetattr(STDIN_FILENO, &trm); /* get the current settings */
trm.c_cc[VMIN] = 1; /* return after 1 byte read; you might make this a 2*/
trm.c_cc[VTIME] = 0; /* block forever until 1 byte is read */
tcsetattr(STDIN_FILENO, TCSANOW, &trm);
}
I want to make a program that forces it's user to input text but doesn't allow him to erase any of it, what's a simple way of doing it in C?
The only thing I've got is (c = getchar()) != EOF && c != '\b' which doesn't work. Any ideas?
POSIX - unix version
#include <sys/types.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
int
main()
{
int fd=fileno(stdin);
struct termios oldtio,newtio;
tcgetattr(fd,&oldtio); /* save current settings */
memcpy(&newtio, &oldtio, sizeof(oldtio));
newtio.c_lflag = ICANON;
newtio.c_cc[VERASE] = 0; /* turn off del */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
/* process user input here */
tcsetattr(fd,TCSANOW,&oldtio); /* restore setting */
return 0;
}
You can't do it with portable code -- essentially every OS has some sort of minimal buffering/editing built into the standard input stream.
Depending on the OSes you need to target, there's a good change you'll have a getch available that will do unbuffered reading. On Windows, you include <conio.h> and go for it. On most Unix, you'll need to include (and link to) curses (or ncurses) for it.
This is likely more complicated than you imagine. To do this, you'll presumably need to take over control of echoing the characters the user is typing etc.
Have a look at the curses library. The wgetch function should be what you need, but first you'll need to initialise curses etc. Have a read of the man pages - if you're lucky you'll find ncurses or curses-intro man pages. Here's a snippet:
To initialize the routines, the routine initscr or newterm must be
called before any of the other routines that deal with windows and
screens are used. The routine endwin must be called before exiting.
To get character-at-a-time input without echoing (most interactive,
screen oriented programs want this), the following sequence should be
used:
initscr(); cbreak(); noecho();
Most programs would additionally use the sequence:
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
If you've not got that manpage / for further info, look up the individual function man pages.
In most modern shells, you can hit the up and down arrows and it will put, at the prompt, previous commands that you have executed. My question is, how does this work?!
It seems to me that the shell is somehow manipulating stdout to overwrite what it has already written?
I notice that programs like wget do this as well. Does anybody have any idea how they do it?
It's not manipulating stdout -- it's overwriting the characters which have already been displayed by the terminal.
Try this:
#include <stdio.h>
#include <unistd.h>
static char bar[] = "======================================="
"======================================>";
int main() {
int i;
for (i = 77; i >= 0; i--) {
printf("[%s]\r", &bar[i]);
fflush(stdout);
sleep(1);
}
printf("\n");
return 0;
}
That's pretty close to wget's output, right? \r is a carriage-return, which the terminal interprets as "move the cursor back to the start of the current line".
Your shell, if it's bash, uses the GNU Readline library, which provides much more general functionality, including detecting terminal types, history management, programmable key bindings, etc.
One more thing -- when in doubt, the source for your wget, your shell, etc. are all available.
To overwrite the current standard output line (or parts of it) use \r (or \b.) The special character \r (carriage return) will return the caret to the beginning of the line, allowing you to overwrite it. The special character \b will bring the caret back one position only, allowing you to overwrite the last character, e.g.
#include <stdio.h>
#include <unistd.h>
int i;
const char progress[] = "|/-\\";
for (i = 0; i < 100; i += 10) {
printf("Processing: %3d%%\r",i); /* \r returns the caret to the line start */
fflush(stdout);
sleep(1);
}
printf("\n"); /* goes to the next line */
fflush(stdout);
printf("Processing: ");
for (i = 0; i < 100; i += 10) {
printf("%c\b", progress[(i/10)%sizeof(progress)]); /* \b goes one back */
fflush(stdout);
sleep(1);
}
printf("\n"); /* goes to the next line */
fflush(stdout);
Use fflush(stdout); because standard output is usually buffered and the information may not otherwise be immediately printed on the output or terminal
In addition to \r and \b, take a look at ncurses for some advanced control over what's on the console screen. (Including columns, moving around arbitrarily, etc).
A program running in a text terminal / console can manipulate the text displayed in its console in various ways (make text bold, move cursor, clear screen etc.). This is accomplished by printing special character sequences, called "escape sequences" (because they usually start with Escape, ASCII 27).
If stdout goes to a terminal which understands these escape sequences, the display of the terminal will change accordingly.
If you redirect stdout to a file, the escape sequences will appear in the file (which is usually not what you want).
There is no complete standard for escape sequences, but most terminals use the sequences introduced by VT100, with many extensions. This is what most terminals under Unix/Linux (xterm, rxvt, konsole) and others like PuTTY understand.
In practice, you would not directly hardcode escape sequences into your software (though you could), but use a library to print them, such as ncurses or GNU readline mentioned above. This allows compatibility with different terminal types.
It's done with the readline library... I'm not sure how it works behind the scenes but I don't think it has anything to do with stdout or streams. I suspect readline uses some sort of cryptic (to me, at least) terminal commands - that is, it cooperates with the terminal program that actually displays your shell session. I don't know that you can get readline-like behavior just by printing output.
(Think about this: stdout can be redirected to a file, but the up/down-arrow keys trick doesn't work on files.)
You can use carriage return to simulate this.
#include <stdio.h>
int main(int argc, char* argv[])
{
while(1)
{
printf("***********");
fflush(stdout);
sleep(1);
printf("\r");
printf("...........");
sleep(1);
}
return 0;
}
The program does this by printing special characters that the terminal interprets in a special way. The most simple version of this is (on most linux/unix terminals) to print '\r' (carriage return) to the normal stdout which resets the cursor position to the first character in the current line. So the thing you write next will overwrite the line you wrote previously. This can be used for simple progress indicators, for example.
int i = 0;
while (something) {
i++;
printf("\rprocessing line %i...", i);
...
}
But there are more complicated escape characters sequences that are interpreted in various ways. All kinds of things can be done with this, like positioning the cursor at a specific position on the screen or setting the text color. If or how these character sequences are interpreted depends on your terminal, but a common class supported by most terminals are ansi escape sequences. So if you want red text, try:
printf("Text in \033[1;31mred\033[0m\n");
The simplest way is to print to stdout the carriage return character ('\r').
The cursor will be moved to the start of the line, allowing you to overwrite its contents.