2

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;
  }
Bart
  • 19,692
  • 7
  • 68
  • 77
UNECS
  • 533
  • 1
  • 9
  • 20
  • If your wondering why I'm doing this, I am trying to get input from stdin and only print to stdout lines that aren't empty. – UNECS Apr 21 '12 at 05:29
  • 1
    If you just want to implement a text filter, it's a very bad idea to bring in terminal control via curses. Interactive character-at-a-time input has nothing to do with the problem of filtering out empty lines. – Kaz Apr 21 '12 at 05:35
  • 1
    To copy nonempty lines from stdin to stdout, try `grep '.'`. I can assure you that it doesn't use ncurses. – Kaz Apr 21 '12 at 05:36
  • @Kaz; I have used character-at-a-time filtering sucessfully with a redirected stdin file but when using it just with stdin the terminal echos the stdin which i don't want. So Hence why I'm Trying terminal control – UNECS Apr 21 '12 at 05:38
  • All standard text processing tools will echo the input. This is a useful and good thing. `sed`, `awk`, `grep`, you name it. The echoing is not affecting the operation; it is just local feedback in the operating system's TTY driver that enables you to see what the heck you are typing. – Kaz Apr 21 '12 at 05:41
  • @Kaz; Which I don't want in this case. Thanks anyway tho. – UNECS Apr 21 '12 at 05:43
  • 2
    By the by, you should read `getch()` into an `int`, not a `char`. http://stackoverflow.com/questions/8464030/using-int-for-character-types-when-comparing-with-eof – HostileFork says dont trust SE Apr 21 '12 at 05:47
  • +1 for saying it is homework. I cannot comment further from paulsm4 . Look up cursers. – Ed Heal Apr 21 '12 at 05:57
  • @Ed Heal; well its gone well beyond the required homework but I hate it when something won't work the way I want it to so I'm spending heaps of extra time on something I probably won't even submit.. – UNECS Apr 21 '12 at 06:08

2 Answers2

7

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.

Kaz
  • 55,781
  • 9
  • 100
  • 149
  • But it won't solve that lack of carriage return. I updated the answer with more. – Kaz Apr 21 '12 at 05:50
  • Thanks I will have a look at them, it will probably be a lot less sloppy than the way I'm doing it. p.s. `if((c == '\n'))putchar('\r');}` works but very crap code I know. – UNECS Apr 21 '12 at 05:56
  • ;Thanks got it going with `tcsetattr` like a dream after many googlies as to how to set the flags Cheers. – UNECS Apr 21 '12 at 10:28
2

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/

paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • Thanks Bookmarked, and clearly I didn't understand what a window was. – UNECS Apr 21 '12 at 05:42
  • Hi - Kaz is right. If you want terminal control for a text-mode application, Ncurses is a good choice. If you want a simple filter to strip empty lines (as you explained subsequently), just use "sed" or "grep". For example: "`cat myfile|grep '.'` – paulsm4 Apr 21 '12 at 05:45
  • I Would use cat... but this is for homework hence the making of a filter. – UNECS Apr 21 '12 at 05:49