Constantly check for keyboard input while theres already a loop - c

Im creating a little game thats like a keyboard version of guitar hero. I'm almost done, but i'm just confused over one thing. I want to constantly be checking if the player is pressing anything on the keyboard and to see if they are pressing the correct key, but I already have a loop that sleeps every 1 second to update the game, so I cant have another loop running at the same time to constantly check the keyboard input (or can I?). I tried putting the keyboard check inside the game loop, but since it sleeps every second, it sometimes doesnt catch when the player presses the key.
This is my while loop:
while (playing)
{
updateBoard(score, game);
checkKeyPress(game);
Sleep(time);
if (rand() % 2 == 1)
spawnNewLetter(game);
}
updateBoard just prints out the new board, spawnNewLetter is just to spawn a new letter to fall down the board, and checkKeyPress is to check the keyboard input, this is it:
void checkKeyPress(char game[GAME_ROW][GAME_COL])
{
if (_kbhit())
{
switch (_getch())
{
case 97:
checkLetter(game, 'a');
break;
case 98:
checkLetter(game, 'b');
break;
The function goes on, but its just repeating to check for all the letters.
Any help would be appreciated, thanks!

Related

getchar() while user is writing

I'm simulating a tv game in a C prompt program. The player has 60 seconds to guess a word, and when he finds it, he has to press enter to get a new one: the word changes, and the number of words and the time left upgrade.
Because the "enter listener" part is a getchar, I was guessing if it could be possible to do a real-time upgrading of the time left second by second, while waiting for the enter pressing with getchar().
while(1) {
system("clear"); //RAND WORD
parola = parole[rand() % n]; //PRINT WORDS, NEW WORD, SECONDS LEFT
printf("\n\n[%d]\t\t%s\t\t%d", indovinate, parola, secLeft);
gettimeofday(&initTime, NULL);
int initSec = initTime.tv_sec; //WAIT FOR PAYLER TO PRESS ENTER
getchar();
gettimeofday(&tookTime, NULL);
int tookSec = tookTime.tv_sec - initSec; //UPGRADE TIME TOOK
secLeft -= tookSec;
try kbhit(),
It's part of the conio.h library.
It basically checks if a key is pressed. If it isn't you can update the time. if it is you can input the answer.
if(kbhit()){
a = getch();
}
else{
//update time
}
you might want to use getch(), it doesn't need the player to press enter.
There might be better ways to do this than c. (Don't ask me, I don't do stuff like this)
But if It's just a cool project, go ahead.
you can use delay of dos.h with the kbhit() of conio.h
the delay(time) take integer as time to pause the program from execution for that 'time' amount
int i=0;
while (i<60||!kbhit()) // wait till i reach value 60 or key is pressed
{//doing the stuff
i++;}
if (i==60)
printf("\n sorry but the time out you may try next time");```

Simulate key being held down in C and WINAPI

I'm working on a project where I took a Super Nintendo controller, driving it with an Arduino. The Arduino reads the button presses on the controller, and sends it over a serial connection.
I'm working on a receiver program, which will read from the serial port, and then simulate key presses in Windows, so I can use the controller in other programs.
The thing is, I got pretty much everything down. Except there is one issue.
My simulated keypresses aren't actually being held down.
Here is the code for the A button (buttons are active low, so they are 'false' when being pressed)
if(!(buttonState.state_word & B_A))
{
/* If previous state is not pressed, and current is pressed, simulate a keypress */
if(prevState.state_word & B_A)
keybd_event(0x41, 0x41,KEYEVENTF_EXTENDEDKEY | 0,0);
}
else if(buttonState.state_word & B_A)
{
/* If previous state is pressed, and current is not pressed, simulate a key release */
if(!(prevState.state_word & B_A))
keybd_event(0x41, 0x41,KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,0);
}
When I press A on the SNES controller, an A will appear in notepad, for example.
And when I hold the A button on the SNES controller, a single A will appear in notepad, but the terminal will print that the key is being held, like I programmed it to do.
When the button is first pressed from being unpressed, it simulates the keypress. When it's held down, no more calls to simulate a keypress are made. And then when the SNES button is released, the keypress is also released.
Since there is this time between the keydown and the keyup, why is there only a single letter being printed, and not as if the keyboard was being held down and printing repeatedly?
Thanks to all who responded.
I ended up taking a different approach, using SendInput instead this time, and now it works like a charm.
As for the reason while I keep state, the way I saw it was if the button is being held down, I don't want to simulate another keypress each time the controller is polled. So I keep state, such that, if the button is pressed, and next time it is polled it is still being pressed, I won't generate another keypress. It will only be generated when the last state of the controller showed it wasn't pressed.
while(1)
{
prevState = buttonState;
ReadFile( hCOM,
&buttonState.state_word,
2,
&bytesRead,
NULL);
for(i = 0; i < 12; i++)
{
if(!(buttonState.state_word & (1 << i)))
{
/* If previous state is not pressed, and current is pressed, simulate a keypress */
if(prevState.state_word & (1 << i))
{
in[i].ki.dwFlags = KEYEVENTF_SCANCODE;
SendInput(1,&in[i],sizeof(INPUT));
}
}
else if(buttonState.state_word & (1 << i))
{
/* If previous state is pressed, and current is not pressed, simulate a key release */
if(!(prevState.state_word & (1 << i)))
{
in[i].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
SendInput(1,&in[i],sizeof(INPUT));
}
}
}
}

threads in c, how to use them to move a player?

Update my code
So i am working on a 2d game in c, now i am using threads to do different stuff in the same time, to move the player, cars etc.
But somehow i don't get it how can i move my player just one step, i know that the problem lays in my global variable movement. But can figure it how to do it the right way. So i hope someone can help me.
The code is huge so i will not passt all of it but the parts that are interesting for the player movement.
void moveFroggy() {
// froggy.y = SCREEN_HEIGHT - OUTER_BORDER;
if((movement == 'a') && (froggy.x > OUTER_BORDER))
froggy.x--;
if((movement == 'd') && (froggy.x < (SCREEN_WIDTH - OUTER_BORDER)))
froggy.x++;
if ((movement == 'w') && (froggy.y >= (SCREEN_HEIGHT - NUM_LANES - OUTER_BORDER - GRASS_BORDER)))
froggy.y--;
if ((movement == 's') && (froggy.y < (SCREEN_HEIGHT - OUTER_BORDER)))
froggy.y++;
if(movement == 'q')
quit = 1;
if(froggy.y <= (SCREEN_HEIGHT - NUM_LANES - OUTER_BORDER - GRASS_BORDER))
player_won = 1;
movement = '0';
}
Now inside the main we have a while loop that runs all the time, till the player complete the game or quit it.
pthread_create(&input_t, NULL, input_runner, NULL);
while(!quit && !error && !player_lost && !player_won) {
moveFroggy();
moveCarsOnMotorway();
startCar((SCREEN_WIDTH - OUTER_BORDER));
drawScreen();
usleep(GAME_SPEED);
}
pthread_join(input_t, NULL);
So my input_t thread is calling the input_runner function inside that function i get the user input.
void *input_runner(void* arg) {
char input;
if(!player_lost || !player_won){
while((input = getchar()) != EOF){
movement = input;
}
}
pthread_exit(0);
}
Just to know movement is a global variable so i can use it for moveFroggy function. but that is the problem to because it stores "w" and it just repeat itself till the user hit any other command. But it should move the player just one step ahead, so how can i reset the value and how to do proper clean up for threads if one is needed.
I am new in using thread,
Well, it seems the simple way to only move one step would be, at the bottom of moveFroggy() to clear movement value.
As an aside, it looks like you're creating an input-processing thread on every iteration of your game loop; is that really what you intend? If you want an input-processing thread, why not have it run its own loop to constantly read input until the game is over?
I'm also not sure of this overall multithreading strategy, but perhaps it will work for you...
This is not a good use of threads, and will be prone to synchronization errors.
Variables that are accessed by multiple threads must be protected by a mutex or accessed using atomic methods. Failing to do so will result in unpredictable behavior.
In any case, you don't need threads for this. If you want to read from the keyboard without blocking, there are a number of ways of doing that, including:
If on Linux, use the ncurses library, which natively provides non-blocking keyboard input through getch().
If on Windows, use kbhit().
Use fcntl() with F_SETFL to set standard input as non-blocking.
Use select() or poll() to check for input before trying to read.
Avoid the console entirely, and use a graphics library such as SDL.

Using `sleep()` for a time delay [duplicate]

This question already has answers here:
Sleep for milliseconds
(20 answers)
Closed 8 years ago.
I an trying to delay program execution for 200ms and then test if a key was pressed during the delay. How do I do this?
I am tryint to create a simple computer game similar to flappy birds, using C. I want the user to have tiny bit of time (~200ms) to press a key for the bird to jump, or it will fall down, but I am having trouble with implementing the delay.
I've read on some forums [where?] that sleep(100) should give a 100ms delay, but when I do it, I get 100 seconds.
I also tried using sleep(1/5), but the function only takes integers.
Additionally, I need to be able to test if a key was pressed during the 200ms; I read somewhere[where?] that the kbhit function can be used for that, but I have no idea how to use it.
while(!dead) {
sleep(200); // what do I put here to get 200ms?
if (keyWasPressedDuringWait()){ //what do I put here?
notDeadAnimation():
}else{
dead=true;
deadAimation()
}
}
To perform the desired delay, #include <unistd.h> and use usleep(microseconds). (To sleep for 200ms, the call is usleep(200000)).
To test the keyboard strike, #include <conio.h> and use _kbhit() in your test (short for keyboard hit). _kbhit tests if there is a key in the key buffer, but does not get rid of it. You also need to use _getch to retrieve the key, removing it from the key buffer. I'd recommend defining a helper function here:
int clearKeyBuffer(){
int count = 0;
while(_kbhit()){
_getch();
count++;
}
return count;
}
This method will clear all keys currently in the key buffer, and return the number of keys cleared. You can then use this in your test, as if(clearKeyBuffer()) to test if a key has been presses since the last time you tested it.
As for your program flow, you have a lot of extra stuff there. You can get rid of most of it and still be functionally identical:
do {
notDeadAnimation();
usleep(200000);
} while(clearKeyBuffer());
deadAnimation();
However, this has the obvious issue that someone could just
Use usleep() instead of sleep(). The former works in micro seconds.
And use _kbhit()+getch() to discover if a key was pressed and which key was it:
while (!dead) {
usleep(200*1000); // 200 msec
if (_kbhit()) { // if key was pressed during sleep
int key = getch();
// you can check key value here
notDeadAnimation();
} else {
dead = true;
deadAnimation();
}
}

Returning program to pre-triggered state

First this gets triggered:
if ((temperatureChannel[channelID].currentTemperature > temperatureChannel[channelID].highLimit) | (temperatureChannel[channelID].currentTemperature < temperatureChannel[channelID].lowLimit))
activateAlarm(channelID);
Activate alarm is triggered, then from there:
void activateAlarm(int channelID);
{ while (temperatureChannel[channelID].currentTemperature > temperatureChannel[channelID].highLimit || temperatureChannel[channelID].currentTemperature < temperatureChannel[channelID].lowLimit)
{
logSubsystem(temperatureChannel[channelID].currentTemperature);
}
}
Then alarm screen is triggered with following case:
int logSubsystem(int currentTemperature)
case 'F': //if user input is 'F'
case 'f': //if user input is 'f'
currentTemperature--;
printf("your current exceeded temp is %i\n \n", currentTemperature);
if (currentTemperature <= 100 || currentTemperature >= 50);
compareLimit();
break; //exits loop
How do I set up this function so that if the user decrements with F and gets the current temperature to below the limit (<100, or >50), then it will return back to the compareLimit function and the requirement for the high limit/low limit triggered state will be FALSE, returning the program to its original pre-alarm state?
I think you would benefit considerably from thinking a lot about how your program flows. Right now, what I can deduce of your program flow is:
You have an outer loop that checks the temperature, on at least one channel ID. Inside that loop, you have the if statement you first showed us.
Then activate alarm does some other stuff, but loops until the temperature goes down, calling logSubsystem.
logSubsystem then presumably gets some kind of user input, and from there, you want it to call to your initial function, presumably called prepare limit.
The problem with this is that none of these functions ever complete. They all call each other, and you'll eventually get a stack overflow. Nice, since that's the name of this site, but not something you want to aspire to.
What you basically need is a state machine. You need something that keeps track of values, looks at those values, and calls functions that return that operate on those values. There should only be one loop, and it should do all the control of what happens based on what those values are. The good news is, you have all of this in place already. temperatureChannel is keeping track of the values for you, and you have while loops a-plenty.
Let me give you my suggestion of the way I suggest your program should flow:
bool checkTemperatureValuesOutOfRange(int channelID) {
// this is just a convenience, to make the state machine flow easier.
return (temperatureChannel[channelID].currentTemperature > temperatureChannel[channelID].highLimit) || // note the || not just one |
(temperatureChannel[channelID].currentTemperature < temperatureChannel[channelID].lowLimit);
}
void actOnUserInput() {
char input = // ... something that gets a user input. It should check if any is available, otherwise return.
switch (input) {
case 'F':
case 'f':
temperatureChannel[channelID].currentTemperature--;
break; // This doesn't exit the loop - it gets you out of the switch statement
}
void activateAlarm(int channelID) {
// presumably this does something other than call logSubsystem?
// if that's all it does, just call it directly
// note - no loop here
logSubsystem(channelID);
}
void logSubsystem(int channelID) { // Not the current temperature - that's a local value, and you want to set the observed value
// I really think actOnUserInput should be (an early) part of the while loop below.
// It's just another input for the state machine, but I'll leave it here per your design
// Presumably actually logs things, too, otherwise it's an unnecessary function
actOnUserInput();
}
while (TRUE) { // this is the main loop of your function, and shouldn't exit unless the program does
// do anything else you need to - check other stuff
// maybe have a for loop going through different channelIDs?
if (checkTemperatureValuesOutOfRange(channelID)) {
activateAlarm(channelId);
// do anything else you need to
}
I'm sure you can see lots of differences between your code and mine. Here are some key things to consider:
All the functions now return. The master while loop calls functions that check status, and calls function that change status.
I would highly suggest acting on the user input as part of the master while loop. It's just another input to the state machine. Get it, act on it, and then check your statuses. You presumably need to have some input from the user, otherwise you'll never get in a bad state in the first place.
Right now, activate alarm happens every time. With the code you showed, that's fine - because logSubsystem was all that was being called. If you only want the alarm to ring once, keep a boolean tracker inside temperatureChannel[channelId] that says if the alarm rang, set it true within activateAlarm, and then reset it to false based on the return value of checkTemperatureValuesOutOfRange.
Rather than leaving yourself in the activateAlarm/logSubsystem area, you return each time, and check your values each time to see if you're still there. This is the key point - your functions should be fast, and not monopolize your processor. Make each function do just one sort of thing, and have all the control come from within the master loop.
I made a lot of changes to your code, and I don't know if you're allowed to make all of them, but you'll need something similar to this. It's much more robust, and gives you room to grow all around.

Resources