Home > Enterprise >  How to ignore "key-up events" while using ReadConsoleInput
How to ignore "key-up events" while using ReadConsoleInput

Time:11-09

There is my code, a simple console program that consists of menu() function for now.

void menu() {
    int k = 0;

    HANDLE s_in = GetStdHandle(STD_INPUT_HANDLE);
    DWORD dr;
    INPUT_RECORD  rec;

    printf("Choose a num\n");
    char vars[] = { '1. A', '2. B', '3. C' };

    while (true)
    {
        for (int i = 0; i < sizeof(vars) / sizeof(vars[0]); i  ) {
            if (k == i) printf("%c [*]\n", vars[i]);
            else printf("%c\n", vars[i]);
        }

        ReadConsoleInput(s_in, &rec, sizeof(INPUT_RECORD), &dr);
        FlushConsoleInputBuffer(s_in);
        
        if (rec.EventType == KEY_EVENT) {
            if (rec.Event.KeyEvent.bKeyDown) {
                switch (rec.Event.KeyEvent.wVirtualKeyCode) {
                case VK_UP:
                    if (k > 0) k--;
                    break;
                case VK_DOWN:
                    if (k < ((sizeof(vars) / sizeof(vars[0])) - 1)) k  ;
                    break;
                default:
                    printf("Use UP or DOWN arrows\n");
                    break;
                }
            }
        }
        
    }

 
   
}

int main()
{
    menu();
}

Unfortunately, there is one problem that ruins everything. I'm using <windows.h> to read keyboard buttons from console, but ReadConsoleInput() function catches all states of button (pressed and released), so I'm getting double printed vars[] every every time I press a key (up and down arrows in this case). How can "key-ups" be ignored, and only "key-downs" can be catched?

CodePudding user response:

Every time ReadConsoleInput returns, you go through the if and then go back to the beginning of the loop and print the "menu" (vars). ReadConsoleInput returns whenever a button is pressed or released. You can even see that pressing a button that isn't VK_UP or VK_DOWN will print "Use UP or DOWN arrows\n", but then releasing that button will not print this line.

A simple solution is to wrap ReadConsoleInput in a loop to filter out the events you don't want.

do {
    ReadConsoleInput(s_in, &rec, 1, &dr);
    FlushConsoleInputBuffer(s_in);
} while (rec.EventType == KEY_EVENT && !rec.Event.KeyEvent.bKeyDown);

Probably a better solution is to move the menu printing outside of the loop and repeat it at the end of the keydown processing:

for (int i = 0; i < sizeof(vars) / sizeof(vars[0]); i  ) {
    if (k == i) printf("%c [*]\n", vars[i]);
    else printf("%c\n", vars[i]);
}

while (true)
{
    ReadConsoleInput(s_in, &rec, 1, &dr);

    if (rec.EventType == KEY_EVENT) {
        if (rec.Event.KeyEvent.bKeyDown) {
            switch (rec.Event.KeyEvent.wVirtualKeyCode) {
            case VK_UP:
                if (k > 0) k--;
                break;
            case VK_DOWN:
                if (k < ((sizeof(vars) / sizeof(vars[0])) - 1)) k  ;
                break;
            default:
                printf("Use UP or DOWN arrows\n");
                break;
            }

            for (int i = 0; i < sizeof(vars) / sizeof(vars[0]); i  ) {
                if (k == i) printf("%c [*]\n", vars[i]);
                else printf("%c\n", vars[i]);
            }
        }
    }
}

The menu printing should really be a function at this point, so you don't have to repeat these lines of code. Note that this also eliminates the need for FlushConsoleInputBuffer.

  • Related