1
#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.

dormer
  • 23
  • 4
  • `while` is not a function, is a control loop. And what is the 50 in `Sleep`? seconds, milliseconds? You might be pressing the key when the program is still executing `Sleep`. – Pablo Apr 14 '18 at 16:50
  • 4
    Call getch() only once. – Hans Passant Apr 14 '18 at 16:50
  • You don't use `kbhit` in a standard C11 or C99 program, because it is not standard conforming. You could choose to code specifically for one operating system and its API (in your case, probably the [winapi](https://en.wikipedia.org/wiki/Windows_API)) and in such case you spend weeks studying that API. You could also choose to use some *existing* (perhaps cross-platform) library (look perhaps into [ncurses](https://www.gnu.org/software/ncurses/) or [GTK](http://gtk.org/)....) – Basile Starynkevitch Apr 14 '18 at 16:52
  • 1
    https://stackoverflow.com/q/15603082/841108 could be a duplicate – Basile Starynkevitch Apr 14 '18 at 16:54
  • `if (!kbhit()) { ... } else { int c = getch(); if (c == ukey || c == Ukey) { ... } else if ( c == dkey || c == Dkey) { ... } else if (...)...` or use `switch (c) {...}` – David C. Rankin Apr 14 '18 at 16:54
  • 1
    The cursor control and function keys return *two* key codes through `getch`. I suggest you write a little test program like `while(1) { while(!kbhit()) ; printf("%d\n", getch()); }` to examine what happens. – Weather Vane Apr 14 '18 at 16:55
  • Read also documentation of [_kbhit](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/kbhit) – Basile Starynkevitch Apr 14 '18 at 16:55
  • Thanks guys, yeah, it's the multiple getch() that did it. Now it's working as intended. – dormer Apr 14 '18 at 17:01

1 Answers1

2

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.

nibot
  • 14,428
  • 8
  • 54
  • 58