C Strange kbhit() behavior in delayed infinite loop

885 views Asked by At

I have been testing some things with kbhit() and have found an odd behavior with a delayed infinite loop. In this code sample I have the loop delayed to run 30 times every second.

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>

_Bool IsKeyDown(char c)
{
    if(kbhit())
    {
        char ch1 = getch();
        if(ch1 == c)
            return 1;
    }
    return 0;
}

/*
 * 
 */
int main(int argc, char** argv) {
    while(1)
    {
        if(IsKeyDown('a'))
        {
            printf("HELLO\n");
        }
        if(IsKeyDown('b'))
        {
            printf("HI\n");
        }
        Sleep(1000 / 30);
    }
    return (EXIT_SUCCESS);
}

The issue is, though the first if statement in the loop works fine, the second if statement barely functions. If you hold down the 'a' key in this example, HELLO is printed indefinitely. If you hold down the 'b' key, HI is barely ever printed, if ever.

Why is this behavior occurring?

2

There are 2 answers

0
Sergey Kalinichenko On

This happens because your IsKeyDown has a side effect of consuming the next character from the buffer when kbhit returns true. Since you call IsKeyDown twice in a row, the first invocation "eats up" the 'b', so when it's time to run the second invocation, there's no data in the buffer.

You need to reorganize your code so that IsKeyDown is called only once per loop iteration. Your loop should store its return value, and compare that stored value to the characters that you need (i.e. 'a' and 'b'):

int GetKeyDown() {
    if(kbhit())
    {
        return getch();
    }
    return -1;
}

while(1)
{
    int keyDown = GetKeyDown();
    if(keyDown == 'a')
    {
        printf("HELLO\n");
    }
    if(keyDown == 'b')
    {
        printf("HI\n");
    }
    Sleep(1000 / 30);
}
0
mcleod_ideafix On

Because the first IF consumes the key that is being pressed. Change your code so the key is read once:

int main(int argc, char** argv) {
    char key;

    while(1)
    {
        if (khbit())
            key = getch();
        else
            key = 0;

        if(key == 'a')
        {
            printf("HELLO\n");
        }
        if(key == 'b')
        {
            printf("HI\n");
        }
        Sleep(1000 / 30);
    }
    return (EXIT_SUCCESS);
}