How do I turn off or ignore key repeat for my curses application?

2.1k views Asked by At

So I recently found curses (specifically PDcurses) and I'm just getting into it. Right now I'm trying to write a little space shooter type game with it and it's worked fine so far for rendering and getting menu type input, but now when I go into the game, I've noticed that key repeat is pretty bad for action games. I need to be able to hold the key and move my avatar every single frame that the key is down. I know how to do this with a normal Win32 application, but I don't have a window and therefore I don't have a wndproc and I can't control the messages the console recieves :/

I don't expect this is something for curses to handle, though if it can that would be awesome, I was really just looking for a work-around that plays nicely with curses.

I have tried cbreak(), nodelay() and raw() to no avail.

Additional info:

  • Microsoft Visual Studio 2010 Ultimate
  • PDcurses 3.4, from prebuilt binaries
  • Windows 7 x64 Ultimate
1

There are 1 answers

4
Managu On

This is far from a complete solution, and I don't know how it'll interact with PDCurses, but it's an attempt:

In summary, grab the console's handle with GetStdHandle(), configure it for raw reading with SetConsoleMode(), and then read keys one at a time with ReadConsoleInput(). I use a std::set to keep track of the currently pressed keys and so ignore repeats.

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <cassert>
#include <set>

int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
    DWORD mode;
    BOOL success;
    success=GetConsoleMode(h, &mode);
    assert(success);
    mode &= ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT);
    mode |= ENABLE_WINDOW_INPUT;
    success=SetConsoleMode(h, mode);
    assert(success);

    INPUT_RECORD buffer[10];
    std::set<WORD> keys_down;
    while (true)
    {
        DWORD count=0;
        success=ReadConsoleInput(h, buffer, 10, &count);
        if (!success)
        {
            continue;
        }
        for (size_t i=0;i<count;++i)
        {
            switch (buffer[i].EventType)
            {
            case KEY_EVENT:
            {
                WORD keycode=buffer[i].Event.KeyEvent.wVirtualKeyCode;
                if (buffer[i].Event.KeyEvent.bKeyDown)
                {
                    if (keys_down.find(keycode)==keys_down.end())
                    {
                        std::cout<<"Key down: "<<keycode<<std::endl;
                        keys_down.insert(keycode);
                    }
                }
                else
                {
                    if (keys_down.find(keycode)!=keys_down.end())
                    {
                        std::cout<<"Key up:"<<keycode<<std::endl;
                        keys_down.erase(keycode);
                    }
                }
                break;
            }
            default: 
                break;
            }
        }
    }
}