SDL/C EventHandler continuous key - c

I'm trying to develop an event handler in C using SDL.
I wanted to be able to detect the following things: Key pressed, key released and key held down.
The problem is that keyboard auto-repeat spams pressed keys after a certain delay and at a given interval. To mitigate this I tried using SDL_EnableKeyRepeat(0, 0); which according to documentation should disable it?
As that failed I tried mapping SDL_GetKeyboardState(NULL); and it sort of works. But I'm having the issue that if i hold down a key for X seconds, it will spam ghost events for the same amount of time.
An example output from pressing esc, holding it down for a bit, and then releasing it is:
Pressed
HELD
HELD
HELD
...
RELEASED {it breaks down after first proper release}
PRESSED
RELEASED
HELD
PRESSED
RELEASED
HELD
...
RELEASED // it always ends on released.
The result from above is:
Pressed: 18;
Released: 21;
Held: 39.
Should be:
Pressed 1;
Released 1;
Held: say 20.
Not sure if I'm messing up my logic somehow, or if it's something with the actual built in mechanics of keyboard events.
Here is the code:
/**
Program Interface
void ev_handle_start() // Starts the Event Handler.
void ev_handle_stop() // Pauses the Event Handler.
**/
#include <stdio.h>
#include <SDL2/SDL.h>
#include <SDL/SDL.h>
#include "ev_handler.h"
#define PRESSED 1
#define RELEASED 0
#define TMR_FREQ 33
#define MOUSE_RIGHT 1
#define MOUSE_LEFT 3
#define EV_LEFT_CLICK 0
#define EV_LEFT_RELEASE 1
#define EV_RIGHT_CLICK 2
#define EV_RIGHT_RELEASE 3
#define EV_MOUSE_MAX 4
#define MAX_SCANCODES SDL_SCANCODE_MODE
#define EV_DELAY 70
//********************************************************************************************//
// VARIABLES
//********************************************************************************************//
SDL_Event e;
Uint8* keyboardState;
SDL_TimerID ev_timer = NULL; // Timer to callback the search of the code
bool ev_handler_active = false; // Used to determine if the ev_handler() is enabled or not
bool buttonState[EV_MOUSE_MAX]; // Button Stats, either pressed or released
bool evMouseEvent[EV_MOUSE_MAX]; // Used to flag if a mouse events
int evKeyEventStatus[MAX_SCANCODES];
bool evKeyStatePrev[MAX_SCANCODES]; //
bool evKeyStateCur[MAX_SCANCODES]; //
//********************************************************************************************//
// 1 FRONTEND
//********************************************************************************************//
//********************************************************************************************//
// 1.1 MOUSE
// Can only handle left and right mouse buttons.
//********************************************************************************************//
bool evButtonPressed(int button)
{ bool flag = button == SDL_BUTTON_RIGHT || button == SDL_BUTTON_LEFT;
if (!flag) {
printf("ERROR: isButtonPressed(int) received parameter of invalid type.\n");
return false;
}
return buttonState[button];
}
bool evLeftClick()
{
return evMouseEvent[EV_LEFT_CLICK];
}
bool evLeftRelease()
{
return evMouseEvent[EV_LEFT_RELEASE];
}
bool evRightClick()
{
return evMouseEvent[EV_RIGHT_CLICK];
}
bool evRightRelease()
{
return evMouseEvent[EV_RIGHT_RELEASE];
}
//********************************************************************************************//
// 1.2 KEYBOARD
//********************************************************************************************//
bool evKeyHeld(SDL_Scancode sc)
{
return evKeyEventStatus[sc] == 1 || evKeyEventStatus[sc] == 3;
}
bool evKeyPressed(SDL_Scancode sc)
{
return evKeyEventStatus[sc] == 1;
}
bool evKeyReleased(SDL_Scancode sc)
{
return evKeyEventStatus[sc] == 2;
}
//********************************************************************************************//
// 1.3 MANAGE
//********************************************************************************************//
void evSetup()
{
for (int i = 0; i < MAX_SCANCODES; i++) {
evKeyStatePrev[i] = 0;
}
evClearEvents();
}
int j;
void evClearEvents()
{
evMouseEvent[EV_LEFT_CLICK] = false;
evMouseEvent[EV_LEFT_RELEASE] = false;
evMouseEvent[EV_RIGHT_CLICK] = false;
evMouseEvent[EV_RIGHT_RELEASE] = false;
}
//********************************************************************************************//
// 2 BACKEND
//********************************************************************************************//
void ev_handler()
{
while(SDL_PollEvent(&e))
{
switch (e.type)
{
/*Skip unnecessary events*/
case SDL_KEYDOWN:
break;
case SDL_KEYUP:
break;
case SDL_MOUSEMOTION:
break;
case SDL_MOUSEBUTTONDOWN:
buttonState[e.button.button] = PRESSED;
if (e.button.button == SDL_BUTTON_LEFT) {
evMouseEvent[EV_LEFT_CLICK] = true;
}
else if (e.button.button == SDL_BUTTON_RIGHT) {
evMouseEvent[EV_RIGHT_CLICK] = true;
}
break;
case SDL_MOUSEBUTTONUP:
buttonState[e.button.button] = RELEASED;
if (e.button.button == SDL_BUTTON_LEFT) {
evMouseEvent[EV_LEFT_RELEASE] = true;
}
else if (e.button.button == SDL_BUTTON_RIGHT) {
evMouseEvent[EV_RIGHT_RELEASE] = true;
}
break;
case SDL_QUIT:
exit(0);
printf("Quit\n");
break;
default:
break;
}
keyboardState = SDL_GetKeyboardState(NULL);
for (int i = 0; i < MAX_SCANCODES; i++)
{
evKeyStateCur[i] = keyboardState[i];
int sum = evKeyStateCur[i] + evKeyStatePrev[i]*2;
switch (sum) {
case 0:
break;
case 1:
evKeyEventStatus[i] = 1;
break;
case 2:
evKeyEventStatus[i] = 2;
break;
case 3:
evKeyEventStatus[i] = 3;
break;
default: evKeyEventStatus[i] = 0; break;
}
evKeyStatePrev[i] = evKeyStateCur[i];
}
}
}

The problem was that SDL 2.0.4 had a bug where holding down a key sent key releases in-between key presses instead of continuous key presses. Downloading the latest version fixed the issue.

Related

How to return back to the initial screen when button is pressed?

I have three screens in the LCD connected to the 8051-microcontroller that scroll to the different screen when the button is pressed but I want to return back to the initial screen when again button is pressed. How can I do that, thank you?
#include <stdio.h>
#include <string.h>
#include <stdint.h>
void change_screen(void);
int count = 0;
void change_screen(void)
{
if (modebutton == 1) { // when button is pressed
if (count == 0) {
count++;
delay(100);
display_screen1();
modebutton=0;
}
else if (count == 1) {
count++;
delay(100);
display_screen2();
modebutton=0;
}
else if (count == 2) {
display_screen3();
count = 0;
}
}
}
You can use the remainder operator % for this.
Example:
void change_screen(void) {
static unsigned count = 0;
if(modebutton) {
delay(100);
modebutton = 0;
switch(count) {
case 0: display_screen1(); break; // first fourth ...
case 1: display_screen2(); break; // second fifth
case 2: display_screen3(); break; // third sixth
}
count = (count + 1) % 3; // 0,1,2 then 0,1,2 etc...
}
}

QMK RGB saturation bottoms out

RGB keycodes RGB_HUI, RGB_HUD, RGB_SAI, RGB_SAD, RGB_VAI, and RGB_VAD allow me to increment or decrement hue, saturation, and value on my RGB underglow lights. But I wanted to be able to hold down a key to change the color continually. So I made these changes:
In config.h:
#ifdef RGBLIGHT_ENABLE
#define RGBLIGHT_HUE_STEP 1
#define RGBLIGHT_SAT_STEP 1
#define RGBLIGHT_VAL_STEP 1
#endif
And then in keymap.c I made the custom keycodes:
enum custom_keycodes {
KC_HUI = SAFE_RANGE,
KC_HUD,
KC_SAI,
KC_SAD,
KC_VAI,
KC_VAD
};
And defined some variables:
// flags. 0 = no change, 1 = increment, -1 = decrement.
int8_t change_hue = 0;
int8_t change_saturation = 0;
int8_t change_value = 0;
// timers to control color change speed
uint16_t hue_timer = 0;
uint16_t saturation_timer = 0;
uint16_t value_timer = 0;
// seconds it takes to cycle through 0-255 or back
// technically 1 = 1.024 seconds, yielding even multiples of 4ms per tick (1024 / 256).
const int8_t hue_seconds = 5;
const int8_t saturation_seconds = 5;
const int8_t value_seconds = 5;
Then I use the keycodes to set the flags and timers:
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case KC_HUI:
if (record->event.pressed) {
hue_timer = timer_read();
change_hue = 1;
} else {
change_hue = 0;
}
break;
case KC_HUD:
if (record->event.pressed) {
hue_timer = timer_read();
change_hue = -1;
} else {
change_hue = 0;
}
break;
case KC_SAI:
if (record->event.pressed) {
saturation_timer = timer_read();
change_saturation = 1;
} else {
change_saturation = 0;
}
break;
case KC_SAD:
if (record->event.pressed) {
saturation_timer = timer_read();
change_saturation = -1;
} else {
change_saturation = 0;
}
break;
case KC_VAI:
if (record->event.pressed) {
value_timer = timer_read();
change_value = 1;
} else {
change_value = 0;
}
break;
case KC_VAD:
if (record->event.pressed) {
value_timer = timer_read();
change_value = -1;
} else {
change_value = 0;
}
break;
}
return true;
}
Then I use a matrix scan to change the color using those flags and timers:
void matrix_scan_user(void) {
switch (change_hue) {
case 0:
break;
case 1:
if (timer_elapsed(hue_timer) > (hue_seconds * 4)) {
hue_timer = timer_read();
rgblight_increase_hue();
}
break;
case -1:
if (timer_elapsed(hue_timer) > (hue_seconds * 4)) {
hue_timer = timer_read();
rgblight_decrease_hue();
}
break;
}
switch (change_saturation) {
case 0:
break;
case 1:
if (timer_elapsed(saturation_timer) > (saturation_seconds * 4)) {
saturation_timer = timer_read();
rgblight_increase_sat();
}
break;
case -1:
if (timer_elapsed(saturation_timer) > (saturation_seconds * 4)) {
saturation_timer = timer_read();
rgblight_decrease_sat();
}
break;
}
switch (change_value) {
case 0:
break;
case 1:
if (timer_elapsed(value_timer) > (value_seconds * 4)) {
value_timer = timer_read();
rgblight_increase_val();
}
break;
case -1:
if (timer_elapsed(value_timer) > (value_seconds * 4)) {
value_timer = timer_read();
rgblight_decrease_val();
}
break;
}
}
According to the docs, each of those should wrap around at the max/min hue/saturation/value, respectively.
That seems to work exactly as expected with KC_HUI and KC_HUD: If I hold the key down long enough it rounds the bend and hue just keeps on cycling through.
KC_SAI, KC_VAI, and KC_VAD work at least normal-ish. I can increase saturation or value to the max and it will just stop there, and likewise if I decrement the value it stops at zero.
KC_SAD is the problem. When I hold it down long enough (just past white), the keyboard bombs out. It turns a weird orange color and nothing works.
For reference, here is the GitHub commit where I made all the changes, along with the rest of my code of course.
Any idea why KC_SAD would bomb out rather than either stopping or wrapping around?
Any idea why both saturation and value just stop, rather than wrapping around as I'd expect based on my read of the docs?
Might I do better to try this whole thing a different way (question to more seasoned users)?
I experimented with this some more, and came up with a different implementation which is much more efficient in terms of lines of code and bytes added to the firmware size. Note that instead of defining new custom keycodes, instead it hijacks the existing RGB_... ones for this new and improved purpose:
#include <lib/lib8tion/lib8tion.h>
// flags. 0 = no change, 1 = increment, -1 = decrement.
int8_t change_hue = 0;
int8_t change_sat = 0;
int8_t change_val = 0;
// timer to control color change speed
uint16_t change_timer = 0;
const uint16_t change_tick = 15;
void matrix_scan_user(void) {
if (change_hue != 0 || change_val != 0 || change_sat != 0) {
if (timer_elapsed(change_timer) > change_tick) {
HSV hsv = rgblight_get_hsv();
hsv.h += change_hue;
hsv.s = change_sat > 0 ? qadd8(hsv.s, (uint8_t) change_sat) : qsub8(hsv.s, (uint8_t) -change_sat);
hsv.v = change_val > 0 ? qadd8(hsv.v, (uint8_t) change_val) : qsub8(hsv.v, (uint8_t) -change_val);
rgblight_sethsv_noeeprom(hsv.h, hsv.s, hsv.v);
change_timer = timer_read();
}
}
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
switch (keycode) {
// clang-format off
case RGB_HUI: change_timer = timer_read(); change_hue = 1; return false;
case RGB_HUD: change_timer = timer_read(); change_hue = -1; return false;
case RGB_SAI: change_timer = timer_read(); change_sat = 1; return false;
case RGB_SAD: change_timer = timer_read(); change_sat = -1; return false;
case RGB_VAI: change_timer = timer_read(); change_val = 1; return false;
case RGB_VAD: change_timer = timer_read(); change_val = -1; return false;
// clang-format on
}
} else {
bool rgb_done = false;
switch (keycode) {
case RGB_HUI:
case RGB_HUD:
change_hue = 0;
rgb_done = true;
break;
case RGB_SAI:
case RGB_SAD:
change_sat = 0;
rgb_done = true;
break;
case RGB_VAI:
case RGB_VAD:
change_val = 0;
rgb_done = true;
break;
}
if (rgb_done) {
HSV final = rgblight_get_hsv();
rgblight_sethsv(final.h, final.s, final.v);
}
}
return true;
}
This is a really nice bit of functionality!
I copied your code into one of my keyboards, and I am not able to reproduce the "bomb out" behavior that you are seeing on KC_SAD.
The documentation is incorrect. The increase/decrease functions for saturation and value do not wrap around, and to my knowledge, they are not intended to wrap. They max out at 255, and are bottom limited at 0. I'll be filing a PR to fix the documentation.
The only significant problem that I see with your implementation is that it results in VERY many writes to eeprom, and that isn't healthy (they wear out over time). You should use, for instance, rgblight_increase_sat_noeeprom() to adjust the saturation (and its counterparts for hue / saturation, and for decrease). Then when you release the key, only then should you write the current HSV setting to eeprom (using rgblight_sethsv() to set the final value into eeprom.

RPi 4 GPIO Interrupt on Rising and Falling trigger not working in C

Beginner here learning to code linux kernel modules.
I want to write a kernel module for my RPi 4 in C language.
I want to use interrupts to light on a LED when I push a button. As long as the button is pushed, the LED is on and when I release it, the LED is supposed to turn off.
I use the function request_irq() so that my function handling the interrupt is called on the rising edge and on the falling edge of my button by indicating "IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING". I formerly used the function gpio_to_irq(BUTTON_PIN).
request_irq(button_irq, button_ih, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "button_irq", NULL);
The function is called when I push the button but not when I release it. It is coded as seen below :
static irqreturn_t button_ih(int irq, void *data)
{
int state;
state = gpio_get_value(BUTTON_PIN);
printk(KERN_INFO "Actual state of the button : %d", state);
//Debounce condition
if(jiffies - last_interrupt_time > msecs_to_jiffies(200))
{
if(state)
{
gpio_set_value(LED_PIN, 1);
}else
{
gpio_set_value(LED_PIN, 0);
}
}
last_interrupt_time = jiffies;
return IRQ_HANDLED;
}
I check whether the value of the button is 1 (pressed) or 0 (released) and want to turn on/off the LED accordingly.
When I try different GPIOs, sometimes, the value of my button is 1 even though I haven't pushed it yet(by printing a message from the init function) and sometimes it's 0. So I don't understand if I'm doing something wrong. I don't think the GPIOs are already used cause I can request them with the function gpio_request_one().
So when the button already has the value 1, the LED turn on but won't switch off when I release the button.
And when the value is already 0, the button value doesn't change to become 1 when I enter the interrupt handler function (and the LED obviously doesn't turn on).
Could you tell me what's wrong with it please?
Form simple C program, not kernel module
This minimal to see how I'm doing.
main.h
typedef struct s_Data {
int exitFlag;
struct {int value; int bcmPin;} In01; //<--- Stock actual GPIO Value
struct {int value; int bcmPin;} In02;
....
struct {int value; int bcmPin;} Out01;
struct {int value; int bcmPin;} Out02;
....
} t_Data;
#define NO_Click 0
#define SimpleClick 1
#define LongClick 2
#define MultiClick 3
typedef struct s_Button {
pthread_t button_thread;
int *exitFlag;
int * input; //Button
int * output;
int old_state;
int new_state;
struct timeval t0;
struct timeval t1;
struct timeval pressedTime;
struct timeval releasedTime;
int clickType;
//float debounce = 0.020; // ms debounce period to prevent flickering when pressing or releasing the button
// debounce not necessary while thread have time to take a coffee
float DCgap; // max ms between clicks for a double click event
float holdTime; // ms hold period: how long to wait for press+hold event
} t_Button;
main.c
#include "main.h"
#include <wiringPi.h>
#include <pthread.h>
// initial state
static t_Data data = {
.exitFlag = 0,
.In01.value = 0, .In01.bcmPin = 4,
.In02.value = 0, .In02.bcmPin = 17,
.Out01.value = 0, .Out01.bcmPin = 4,
.Out02.value = 0, .Out02.bcmPin = 17,
}
static _Data data_prev;
static void *inputRead_threadFn(void *p_Data) {
pinMode(Data.In01.bcmPin, INPUT);
pullUpDnControl(Data.In01.bcmPin, PUD_UP);
pinMode(Data.In02.bcmPin, INPUT);
pullUpDnControl(Data.In02.bcmPin, PUD_UP);
while (!Data.exitFlag) {
Data.In01.value = !digitalRead(Data.In01.bcmPin);
Data.In02.value = !digitalRead(Data.In02.bcmPin);
if (Data.In01.value != Data_old.In01.value) {
Data_old.In01.value = Data.In01.value;
}
if (Data.In02.value != Data_old.In02.value) {
Data_old.In02.value = Data.In02.value;
}
usleep(50)
}
}
static void *outputWrite_threadFn(void *p_Data) {
pinMode(Data.In01.bcmPin, OUTPUT);
pinMode(Data.In02.bcmPin, OUTPUT);
while (!Data.exitFlag) {
digitalWrite(Data.Out01.bcmPin, !Data.Out01.value);
digitalWrite(Data.Out02.bcmPin, !Data.Out02.value);
}
usleep(50)
}
static void *button_threadFn(void *p_Data) {
t_Button *button = (t_Button *)p_data;
LOG("Button[%s] thread initialized\r\n", button->name);
button->old_state = 0;
button->new_state = 0;
button->clickType = NO_Click;
int clickCount = 0;
while(*(button->exitFlag) == 0) {
button->new_state = *(button->input) || *(button->web_input); //*((int *)
if( button->old_state == 0 && button->new_state == 1 ) {
//printf("front montant\r\n"); fflush(stdout);
// *****************************
// traitement sur front montant
// rising edge
// *****************************
button->old_state = 1;
gettimeofday(&button->pressedTime, 0);
//Button pressed
} else if( (button->old_state == 1) && (button->new_state == 0) ) {
//printf("front descendant\r\n"); fflush(stdout);
// *****************************
// traitement sur front descendant
// falling edge
// *****************************
button->old_state = 0;
gettimeofday(&button->releasedTime, 0);
if (my_timedifference_msec(button->releasedTime, button->pressedTime ) < button->DCgap) {
clickCount++;
button->clickType = MultiClick;
}
//Button released
} else if( (button->old_state == 0) && (button->new_state == 0) ) {
// printf("front bas\r\n"); fflush(stdout);
// *****************************
// pas de changement d'état : front bas
// no state change : edge down
// *****************************
gettimeofday(&button->t0, 0);
*(button->output) = 0; //<--- here in your case
//Attendre DC_Gap pour connaitre le nombre de click
// Wait for DC_Gap to know click count
if (my_timedifference_msec(button->t0, button->releasedTime) > button->DCgap) {
if (clickCount == 1) {
LOG("SimpleClick");
//Simple Click
} else if ( clickCount > 1 ) {
//Multiclicks
}
button->clickType = NO_Click;
clickCount = 0;
}
} else if( (button->old_state == 1) && (button->new_state == 1) ) {
// printf("front haut\r\n"); fflush(stdout);
// *****************************
// pas de changement d'état : front haut
// no state change : edge up
// *****************************
gettimeofday(&button->t1, 0);
*(button->output) = 1; //<--- here in your case
//long click
if (my_timedifference_msec(button->t1, button->pressedTime) >= button->holdTime) {
LOG("LongClick");
button->clickType = LongClick;
//do what you want while not released
usleep(30*1000);
}
}
usleep(100);
}
printf("Light Loop::exiting...\r\n"); fflush(stdout);
}
int main(int argc, char** argv) {
wiringPiSetup();
wiringPiSetupGpio();
data_prev = data;
//start input thread
//start output thread
int DCGap = 250; //ms
int HoldTime = 600;
t_Button Buttons[] = {
{ //WC
.exitFlag = &Data.exitFlag,
.DCgap = DCGap,
.holdTime = HoldTime,
.input = &Data.In01.value,
.output = &Data.Out01.value,
},
{ //chambre
.exitFlag = &Data.exitFlag,
.DCgap = DCGap,
.holdTime = HoldTime,
.input = &Data.In02.value,
.output= &Data.Out02.value,
}
}
//start buttons threads
for (i = 0; i < (sizeof(Buttons) / sizeof(t_Button)) ; i++) {
ret = pthread_create (&Buttons[i].button_threadFn, NULL, fn_Button, &Buttons[i]);
if (ret) {
fprintf (stderr, "%s", strerror (ret));
}
}
//threads join
return (EXIT_SUCCESS);
}
Ok so thanks for all the comments/answers.
It was indeed because I wasn't using any pull-up or pull-down resistor properly.
So I changed my circuit as following:
Circuit

Double buffering and printf

I am having trouble with getting my other basic functions to work with double buffer.
for example in the code below, it runs and I can press either down or up to move my cursor, and when I press enter I am supposed to get a printf saying either making a new char, load, or goodbye.
It shows up for a split second but then it immediately disappears. In these situations rewind(stdin) and getchar(); solves this issue but for this code, nothing seems to work.
Please help.
#define _CRT_SECURE_NO_WARNINGS
#include "conioex.h"
#include "DblBuffer.h"
enum //
{
NEW_GAME = 20,
LOAD,
EXIT,
MAX_NUM
};
void main (void)
{
DblBuffer db;
int Cursor_X, Cursor_Y; // cursorlocation
bool Key_flag = false; // pressandtrue
int type = NEW_GAME; // type
Cursor_X = 20;
Cursor_Y = 1;
int flag = 1;
while (flag)
{
for (int i = 1; i <= 3; i++)
{
db.setCursorPos(20,i);
db.write(" ");
}
db.setCursorPos(25,1);
db.write("New Game\n");
db.setCursorPos(25,2);
db.write("Load\n");
db.setCursorPos(25,3);
db.write("Exit\n");
if (inport(PK_DOWN))
{
if (Key_flag == false)
{
Cursor_Y = Cursor_Y + 1;
type = type + 1;
Key_flag = true;
}
}
else if (inport(PK_UP))
{
if (Key_flag == false)
{
Cursor_Y = Cursor_Y - 1;
type = type - 1;
Key_flag = true;
}
}
else if (inport(PK_ENTER))
{
flag = 0;
break;
}
else
{
Key_flag = false;
}
if (Cursor_Y < 1)
{
Cursor_Y = 1;
}
if (Cursor_Y > 3)
{
Cursor_Y = 3;
}
if (type < NEW_GAME)
{
type = NEW_GAME;
}
if (type >= MAX_NUM)
{
type = MAX_NUM - 1;
}
db.setCursorPos(Cursor_X, Cursor_Y);
db.write("→");
db.swap();
}
if(type == NEW_GAME)
{
printf("making a new game");
}
if (type == LOAD)
{
printf("will load");
}
if (type == EXIT)
{
printf("goodbye");
}
rewind(stdin);
getchar();
}
As for your problem, by "then it immediately disappears" I assume that the console window disappears quickly?
That's because the program exits.
You need to flush the input buffer connected to stdin to remove all key presses you made (by reading from stdin) and then call getchar one extra time to get a a kind of confirmation that the user wants to exit.

sdl getting continuously key pressing

I am currently programming a simple game in SDL (PONG clone) where i must have a continuously key pressing.
The problem I have is that when i press a button it reacts, waits a short period and then continues to continuously key pressing.
I wonder how i get that little delay to go away.
Here is my code:
while (running)
{
while (SDL_PollEvent(&event))
{
//update the game
if (event.type == SDL_QUIT)
{
quit_game();
running = false;
}
if(event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_DOWN:
move_paddle(UP);
break;
case SDLK_UP:
move_paddle(DOWN);
break;
default:
break;
}
}
}
draw_game();
move_ball();
SDL_Delay(15);
}
The first thing i did was i wanted to remove the small delay and get the movement of the paddle smoother. I introduced 2 new global bool variables to keep track on which key that was pressed down.
bool key_up = false;
bool key_down = false;
I initiate them with the value false because no key is currently pressed.
In my switch I set the value for these boolean variables to match what is currently pressed down.
if(event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_DOWN:
key_up = true;
key_down = false;
break;
case SDLK_UP:
key_down = true;
key_up = false;
break;
default:
break;
}
}
Then in the first while-loop i make two if-cases for the two keys that can be pressed and call the movement function in these if-cases.
if (key_up)
move_paddle(UP);
else if (key_down)
move_paddle(DOWN);
When i did this the delay disappeared and the paddle movement was smooth but it also generated another probelm, the paddle could not stay still in one place (except the boundraries). I then realised that the code is only looking for a key that is pressed down and does not react to a key that is released.
I then figured out that if a key is released (in this case the UP key or the DOWN key) the two boolean values had to be set to false because no key was pressed down.
What I did was that I made another if-statement after the if(event.type == SDL_KEYDOWN) that would disable the movement of the paddle if no key was pressed down.
if (event.type == SDL_KEYUP)
{
key_down = false;
key_up = false;
}
When I implemented all of this in my code the game worked like a charm.
For those who are interested, here is my new final code:
int gameloop()
{
SDL_Event event;
bool running = true;
bool key_up = false;
bool key_down = false;
while (running)
{
while (SDL_PollEvent(&event))
{
//update the game
if (event.type == SDL_QUIT)
{
quit_game();
running = false;
}
if(event.type == SDL_KEYDOWN)
{
switch (event.key.keysym.sym)
{
case SDLK_DOWN:
key_up = true;
key_down = false;
break;
case SDLK_UP:
key_down = true;
key_up = false;
break;
default:
break;
}
}
if (event.type == SDL_KEYUP)
{
key_down = false;
key_up = false;
}
}
if (key_up)
move_paddle(UP);
else if (key_down)
move_paddle(DOWN);
move_ball();
ai_paddle_move();
draw_game();
printf("Player: %d | AI: %d\n", player, ai);
SDL_Delay(15);
}
return 1;
}

Resources