cconiokbhit

How do I use kbhit in C?


#include<stdio.h>
#include<Windows.h>
#include<conio.h>
#define Ukey 87
#define ukey 119
#define Dkey 115
#define dkey 83
#define Lkey 97
#define lkey 65
#define Rkey 100
#define rkey 68

int main(){
    int x=0;
    int y=0;
    int prev=rkey;
    while(true){
        Sleep(50);
        system("cls");
        printf("x : %d\ny : %d",x,y);

        if(!kbhit()){
            if(prev==ukey){
                y--;
            }else if(prev==dkey){
                y++;
            }else if(prev==lkey){
                x--;
            }else if(prev==rkey){
                x++;
            }
        }else if(getch()==ukey||getch()==Ukey){
            y--;
            prev=ukey;
        }else if(getch()==dkey||getch()==Dkey){
            y++;
            prev=dkey;
        }else if(getch()==lkey||getch()==Lkey){
            x--;
            prev=lkey;
        }else if(getch()==rkey||getch()==Rkey){
            x++;
            prev=rkey;
        }
    }
}

So basically my program detects keyboard key (either w,a,s or d which I defined as Ukey,Dkey,Lkey and Rkey). The program is meant to detect the direction by key-press, change the x and y value and maintain it until another key is pressed.

My problem is that when the program run and the default direction (right) is initialized, the while function just stops when I press another key. It will only keep changing the x and y value if I press the key for a few seconds.

What's wrong with my code? It's my first time using kbhit so your answers would be a huge help for me. Thanks.


Solution

  • I think the problem is in the else if(getch()==ukey||getch()==Ukey) structure, which makes many calls to getch. If kbhit has returned true, then the first call to getch will be non-blocking. However, each additional call will be blocking until a new key is hit.

    Solution: Restructure your program so that there is only one call to getch:

    while (true) {
    
      if (kbhit()) {
        // A key was pressed. Find out which one.
        prev = getch()
      }
    
      switch (prev) {
        case ukey: y--; break;
        case UKey: ...
        ...
      }
    

    }

    Furthermore, it would probably be advantageous to specifically detect the two-character response from arrow keys. I don't remember exactly how it works, but the logic would be something like:

    if (kbhit()) {
     c = getch()
     if (c indicates a control character) {
       c = getch();
       switch c: {
         case up arrow: command = up;
         ...
       }
     }
    }
    

    You may wish to create an enum to store the current "mode" or last command.