0

I'm experminenting with ncurses and I've stumbled upon a bit counter-intuitive behaviour when usinghalfdelay with small delays.

The following expects keyboard input from the user. Rather than just pressing and releasing a key, I'm testing it with the key being pressed so that it should continue printing the corresponding character (more precisely, the corresponding int value). Here's a stripped version of what I have:

#include <ncurses.h>

int main() {
  int c = 0, d = 0, e = 0;

  initscr();
  cbreak();
  noecho();
  keypad(stdscr, TRUE);

  while ('q' != (c = getch())) {
    printw("c: %d\n", c);

    // Make sure that halfdelay returned OK. It should as the input is in the expected range ([1, 255])
    if ((d = halfdelay(1)) != OK) {
      printw("d: %d\n", d);
      return 0;
    }

    e = getch();

    printw("e: %d\n", e);
    cbreak();
  }

  endwin();
  return 0;
}

Here's how I build it and run it:

$ gcc -Wall -Wpedantic -lncurses file.c
$ a.out

And the output when running it (after pressing and holding a on the keyboard for ~1s):

c: 97
e: -1
c: 97
e: 97
c: 97
e: 97
c: 97
e: 97
c: 97
e: 97
c: 97
e: 97
c: 97
e: -1

Question Where is -1/EOF coming from in this output? I did notice that by increasing the delay (from 1 to 7 on my machine) makes the EOF character to go away completely. I would love to understand what's the mechanism causig this.

banach-space
  • 1,781
  • 1
  • 12
  • 27
  • if ((d = (halfdelay(1)) != OK)) ...... you should not write compound expessions that can go wrong:( – Martin James Jun 15 '18 at 13:40
  • I don't think it makes much sense to switch input modes after each character. – Gerhardh Jun 15 '18 at 14:02
  • @MartinJames It's not the most glorious line of code, I admit that. I was checking the actual value returned from `halfdelay`. But what could go wrong there? – banach-space Jun 15 '18 at 14:07
  • @Gerhardh Probably not. I was trying various things and just didn't clean that up, sorry! – banach-space Jun 15 '18 at 14:08
  • 1
    @banach-space did you mean to place the brackets as you did? 'a=b!=c' ? – Martin James Jun 15 '18 at 17:08
  • Actually it's **`ERR`** rather than **`EOF`** (only happens to be the same value). The manual pages tell you this. – Thomas Dickey Jun 15 '18 at 20:01
  • @MartinJames Thanks pal, well spotted! Fixed! – banach-space Jun 16 '18 at 12:19
  • @ThomasDickey Thanks, but I double-checked that by changing the value of *`ERR`* in ncurses.h. It's indeed *`EOF`*. The man pages for `halfdelay` are confusing. You will find there this: `ERR is returned if nothing has been typed`, as well as this: `returns an error if its parameter is outside the range 1..255.` That's contradicting, isn't it? By experimenting I noticed that if nothing's typed, then next call to `getch` returns `EOF`. `ERR` is only returned when the input to `halfdelay` is outside [1, 255]. This agrees with the answer below. – banach-space Jun 16 '18 at 12:25

1 Answers1

2

tl;dr If you type too slow, you don't get a key with getch but you get EOF instead.

Long version:

According to ncurses manual, halfdelay mode means that input functions wait until a key is pressed or a given timeout interval expires. With halfdelay(1) you not only set the input mode to halfdelay but you also set this interval to 1/10 second. This means if you don't get a key within 1/10s, the function returns anyway.

On the other side holding down a key creates multiple key presses. If the speed of these keypresses is too slow to fit into your halfdelay interval, you run out of key presses at some time and will see EOF.

Therefore it is straight forward that you can avoid getting EOF if you increase the interval beyond the interval of key presses.

To verify the numbers you could try to figure out what the key repeat rate for holding down a key is. It's probably less than 7 per second.

Gerhardh
  • 11,688
  • 4
  • 17
  • 39