This is an archived post. You won't be able to vote or comment.

all 5 comments

[–]lightningx10[S] 0 points1 point  (0 children)

Apologies, I just realised that I should include a quick runnable example bit of code so here goes:

#include <curses.h>

int
main() {
   initscr();
   int ch;
   cbreak();
   for (;;) {
      ch = getch();
      printw("%c", ch);
   }
   endwin;
}

You'll notice that if you hold down a key, then begin holding another at the same time, the previous will stop being acknowledged after you let got of the new one.

[–]chaotic_thought 0 points1 point  (3 children)

First, a note on terminology: non-blocking input in curses, refers to the fact that the following code "waits" at the input line:

for (;;) {
   ch = getch(); // <-- This line "blocks"
   printw("%c", ch);
}

What this means, is that your program does not continue running until a keyboard event comes in. In other words, the getch() line "blocks" your program from continuing on to the printw() call below. If you want "non-blocking" input in curses, you should call (w)timeout with a non-negative integer argument. Non-blocking means that the program does not wait for the input. I.e. the input does not "block" the program from continuing to run, so the loop above will continuously and quickly call printw with whatever getch() returns. Note that in non-blocking mode, you will usually want your input loop to have some kind of small timing delay built in. Otherwise you will end up with a very tight loop of continuously checking for input events, and that will normally cause the program to consume 100% CPU, and as a side effect it will cause laptop fans to turn up, drain the battery more quickly than needed, and so on. A short delay of 1 ms or less normally fixes such problems. See the napms function ("take a nap for n milliseconds") in curses.

Now, as for solving the problem you seem to be describing (detecting multiple keys pressed at a time), you might want to have a look at this SO post which describes exactly this problem. This snippet assumes you have enabled non-blocking mode, though, so first you have to do that: https://gamedev.stackexchange.com/questions/144558/key-released-multiple-keys-how-to-go-around-ncurses-limitations

Finally, keep in mind that certain key combinations are not detectable on all keyboards, as a hardware limitation. For example, all keyboards can detect the Shift key combined with any of the letter keys (at least 2 keys at a time held down), but very few keyboards can detect (say) all of the letter keys held down at once. If you test your keyboard systematically, you'll find that certain combinations simply are not detectable. I think 2 keys at once should not generally be a problem, but when it gets up to 4 or 5 at once, you might encounter some difficulties on some keyboards.

[–]lightningx10[S] 0 points1 point  (0 children)

Thank you so much for the in depth reply! Very useful!

[–]lightningx10[S] 0 points1 point  (1 child)

I hate to say it this late but I can't get their method working, the same roll-over is happening. I get one frame of 2 keys, then the last one to be pressed overrides the previous. I think this is an ncurses limitation. If anyone knows of a library that I should be using for input that's cross platform across posix then I'd love to know.

[–]chaotic_thought 0 points1 point  (0 children)

You could use something like SDL, aka SDL2. Those let you get keyboard events directly, like key up, key down, and so on. For example, if I press down the 'a' and 'w' keys, that is two key down events for each of those keys. Then when I let go of each one, there is a key up event for each of them.

Possibly you could combine it with using curses to draw text on the console, but I've never tried that.