2

Working on an assignment for class and have been battling ncurses for a while now (it's new to me). Creating a program that is able to communicate with another instance of the same program across a network. Part of the program is to interactively get characters from keyboard and send them to the receiving side. (We have been advised to do this with single thread approach and using getch in ncurses, with nonblocking input from getch).

The issue I'm running into is that my getch is having behavior I cannot figure out. In different variations, it would either display every other character I type, and it won't display the most recently typed character until another character is typed after it. I've used nodelay() to get the live input, but .

Here is the setup for my ncurses display. (Note: I used noecho() as later I don't want to display every char that is enter).

/* initialize ncurses */
setlocale(LC_ALL,"");
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
clear();

Here is the code I wrote that works with getch and sending/receiving the data over the socket.

while(1) {
    rfdset = master;

    if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
        perror("select");
        exit(EXIT_FAILURE);
    }

    ch = getch();

    if (ch != ERR) {
        printw("%c",ch);
        write(direct, &ch, 1); // direction to send data
    }

    for(i = 0; i <= maxfd; i++) {
        if (FD_ISSET(i, &rfdset)) {
            bzero(msgbuf, MSGSIZE);
            idx = read(i, msgbuf, MSGSIZE);
            if (i != STDIN)
                printw("%s",msgbuf); // display received msg
        }
    }
}

When I run this and type data on any end of the application, I get results as follows:

Computer 1 keyboard input: testing123
Computer 1 screen display: tsig2

Computer 2 message recv'd: tsig2

Because of this, I feel certain that getch is causing most of my issues, and I must be missing or doing something incorrectly in my implementation. Any advice is appreciated.

Edit 1:

I managed to resolve the every other character issue by removing the for loop and just checking the sockets directly for input. I am baffled why this fixed it. Now my only remaining issue is why is a character not displayed until a character is entered after it. Here is my revised code in the while loop:

while(1) {
    rfdset = master;

    if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
        perror("select");
        exit(EXIT_FAILURE);
    }

    ch = getch();

    if (ch != ERR) {
        printw("%c",ch);
        write(direct, &ch, 1);
    }

    /* check for incoming data from left socket */
    if (!NOLEFT && FD_ISSET(lcsad, &rfdset)) {
        bzero(leftmsg, MSGSIZE);
        idx = read(lcsad, leftmsg, MSGSIZE);
        leftmsg[idx] = 0;
        printw("%s", leftmsg);
        lm = 1;
    }

    /* check for incoming data from right socket */
    if (!NORIGHT && FD_ISSET(rsd, &rfdset)) {
        bzero(rghtmsg, MSGSIZE);
        idx = read(rsd, rghtmsg, MSGSIZE);
        rghtmsg[idx] = 0;
        printw("%s", rghtmsg);
        rm = 1;
    }

    /* check and send left message onward */
    if (lm && !NORIGHT) {
        write(direct, leftmsg, MSGSIZE);
    }

    /* check and send right message onward */
    if (rm && !NOLEFT) {
        write(direct, rghtmsg, MSGSIZE);
    }
    lm, rm = 0;
}
J Moonham
  • 35
  • 5

2 Answers2

1

The problem is that because your select call specifies no timeout (the last parameter is NULL), it blocks until there is some pending I/O (such as the next character which you type). At that point, the program continues into the getch call, which does a refresh (echoing the characters from your printw call).

Specifying a short timeout, e.g., 10 milliseconds, would improve things, e.g.,

struct timeval myTimeout;
myTimeout.tv_sec = 0;
myTimeout.tv_usec = 10000;

and pass the address of myTimeout in the call to select...

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • This fixed the issue, thanks for the clear explanation. Adding the timeout to `select` fixed the issue. – J Moonham Jul 12 '17 at 15:38
0

You can try if using wgetch() instead of getch() solves your problem.

  • per recent edit - I fixed the every other char issue, now I'm stuck on the issue of _why is a character not displayed until a character is entered after it._ – J Moonham Jul 10 '17 at 16:18