bug-ncurses
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Fw: Re: keypad & non-default terminal


From: Rob King
Subject: Re: Fw: Re: keypad & non-default terminal
Date: Thu, 4 May 2017 12:20:58 -0500
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.8.0

Hi,

Forgive me if this isn't the appropriate place in which to continue discussing this problem, as I don't believe the problem is a bug in ncurses.

I believe the problem with parsing the keystrokes is due to how things are set up on the client side, specifically with regards to terminal modes and buffering.

The client's terminal must be configured to be in raw mode. This is normally accomplished by calling the (n)curses raw(3) function, but that function only works on local terminals; it doesn't work across a socket.

In other words, you would need to replicate raw(3)'s actions on the client side's terminal before connecting to the remote end. You could accomplish this by simply calling initscr(3) and raw(3) on the client side, but because these functions might have some side effects unrelated to what you're doing here, it might be better to do it the old-fashioned way as described below.

As a quick experiment, I wrote a small TCP server and client and got it working (the server just opens a window and echoes back the typed characters, with A_BOLD turned on). The necessary steps on the client side are:

- STDIN_FILENO was modified to use raw mode (via cfmakeraw(3)). This disables echoing and makes characters available immediately upon typing.

- STDIN_FILENO had its VMIN set to 1 and its VTIME set to 0 via tcsetattr. I'll explain more below.

- The TCP_NODELAY option was set on the socket; this turns off Nagle's algorithm in the TCP stack, meaning small writes aren't batched together, but rather sent immediately. As I said earlier, this is probably overkill but it certainly doesn't hurt.

- A read buffer for standard input was used that was large enough to ensure we captured a whole function key sequence and could send it at once (again probably not strictly necessary, but it doesn't hurt).

- For the sake of completeness, the reads from both the standard input and the socket in the client were managed using select(2) to avoid polling and/or blocking.

When the client terminal is set up this way, and the server is set up as expected (using keypad, etc), things work.

The terminal setup above is manually doing much of what the ncurses raw(3) function does. Because the terminal is on the other side of a socket, the server cannot do this setup for the remote terminal and it must be done manually.

The VMIN setting controls how many characters the terminal will try to read before returning to the reader (in this case our client application), and VTIME controls how long (in 1/10ths of a second) it will wait before timing out if it can't get that many characters. We want the terminal to return characters as quickly as possible, hence the settings there.

Without changing the client terminal's input settings, the terminal will not reliably deliver the characters expected by ncurses for special key sequences close enough together in time (and possibly not at all if the terminal is configured to intercept certain sequences).

Anyway, I hope this helps. Please feel free to email me privately if you have any questions (because I don't think this is a bug in ncurses I don't know if we should continue CC'ing everyone. :)

    Rob

On 05/04/2017 03:30 AM, folkert wrote:
Hi Rob,

Well let's ignore the local echo part, that's probably something to do
with me not sending the correct telnet commands (255, ...etc)

The biggest problem is that ncurses does not parse/process the key
presses correctly. It receives e.g. an ansi byte sequence for page up
but passes that on directly to the program instead of parsing them and
converting them to KEY_NPAGE etc.

On Wed, May 03, 2017 at 03:29:59PM -0500, Rob King wrote:
Hi,

     Calling nodelay, etc. cannot set the other end of the connection's
buffering. Are you in control of the code on the client side? You'll need to
set it to be unbuffered when waiting for input on the client side before
establishing the connection to the server.

     Depending on what you're trying to do, you might also want to set
TCP_NODELAY using setsockopt(2) on the client side, though that might be
overkill.

     Thanks!


(Please note that I am not affiliated with the ncurses project; just trying
to help.)



On 05/03/2017 02:43 PM, folkert wrote:
Hi,

I have a program which accepts network connections and then maps an
ncurses session on them:

void loop()
{
        int fd = accept(...)

          FILE *fh = fdopen(fd, "rw");

          SCREEN *scr = newterm("ansi", fh, fh);
        set_term(scr);

          WINDOW *win = newwin(25, 80, 0, 0);

          start_color();
          cbreak();
          keypad(win, TRUE);
          intrflush(win, FALSE);
          nodelay(win, FALSE);
          meta(win, TRUE);
          idlok(win, TRUE);
          idcok(win, TRUE);
          leaveok(win, FALSE);

        for(;;)
                printf("[%d]", wgetch(win));
}

Now I would expect to get values like 0522 for page down and 0523 for
page down but instead:
- it waits for enter on the screen in which the program is started, NOT
    the network connection
- the key pressed is printed as garbage on the network connection: ^[[5~
- the key is returned as a bunch of characters instead
    ([27][91][53][126])

So it looks like that cbreak and keypad are ignored while wgetch not
only listens on the fd given by newterm but also the regular stdin one.

Hopefully I'm doing something wrong.


regards

_______________________________________________
Bug-ncurses mailing list
address@hidden
https://lists.gnu.org/mailman/listinfo/bug-ncurses
_______________________________________________
Bug-ncurses mailing list
address@hidden
https://lists.gnu.org/mailman/listinfo/bug-ncurses




reply via email to

[Prev in Thread] Current Thread [Next in Thread]