SDL 2 hangs when polling for events - c

I'm working on a simple GUI, and i'm trying to use the SDL library with little success. I'm developing in C language, and i can't switch to C++.
I'm using SDL 2.0.5 on a Linux workstation (Red Hat Enterprise Server 5 (Tikanga)).
The problem is that when i try to catch events, the window hangs. No response, 100% CPU usage, and i've to kill the process. Clicking on the "x" have no effect.
I wrote a simple test code to figure out the problem, but i really don't know what to do. It looks like the inner "printf" it's never reached.
Also, if i remove the event loop, SDL_Quit() is reached (no need to kill the process) and it gives me a "Segmentation fault".
#include <SDL.h>
#include <SDL_events.h>
SDL_Window *mainWin;
SDL_Event mainEv;
int quit = 0;
if(SDL_Init(SDL_INIT_VIDEO) != 0)
{
printf("Init error.\n");
return(1);
}
mainWin = SDL_CreateWindow("Title", 0, 0, 640, 480, 0);
while(!quit)
{
while(SDL_PollEvent(&mainEv))
{
printf("Event!\n");
switch(mainEv.type)
{
case SDL_KEYDOWN:
quit=1;
}
}
}
SDL_Quit();

Try:
#include <SDL2/SDL.h>
//#include <SDL_events.h>
int main(void)
{ SDL_Window *mainWin;
...
... // same up to:
...
case SDL_KEYDOWN:
quit = 1;
...
SDL_Quit();
}
I pasted your code into "sdl_t.c", so compiled it with:
gcc sdl_t.c `sdl2-config --libs --cflags` -o sdl_t
I get a window that pops up and goes away when you press a key. There's obviously more to do ...
Have you seen this good tutorial?
http://www.willusher.io/pages/sdl2/

Related

SDL remembers last instance"s user input

I am working on an SDL project in C and I am having trouble with the input handling.
whenever I start my SDL app it remembers the last app's inputted keys and SDL_PollEvent always gives repeatedly the last key that was pressed in the previous instance of the program.
btw I am compiling the code in a WSL window I have tried the same piece of code in a visual studio environment and it worked perfectly fine. So can someone explain what's happening?
Here is the sample code:
#include <SDL2/SDL.h>
#include <stdio.h>
int main() {
SDL_Event event;
SDL_Window* sdlwind;
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "SDL_Init Error : %s", SDL_GetError());
return 1;
}
sdlwind = SDL_CreateWindow("Engine", 0, 0, 1080, 840, SDL_WINDOW_SHOWN);
if(!sdlwind) {
fprintf(stderr, "SDL_CreateWindow Error : %s", SDL_GetError());
return 1;
}
printf("Start");
while (1)
{
while (SDL_PollEvent(&event))
{
printf("%c\n", event.key.keysym.sym);
}
if(event.key.keysym.sym == SDLK_a) {
break;
}
}
SDL_DestroyWindow(sdlwind);
SDL_Quit();
return 0;
}
This sample code has outputted the first time:
OUTPUT
,
,
,
,
,
,
// etc since the last key pressed in the previous instance was , and after terminating the program by pressing a
// the next output becomes
OUTPUT
a
a
a
a
a
// etc
I have tried removing the executable and launching another SDL program but the same problem persists. I have later tried to take input normally with getchar() but it didn't register any key so I am not sure but it might not be a problem related to the stdin it must be smthng with SDL and WSL.
It sounds like you are experiencing the same root problem as in this Super User question and issue #58 against WSLg.
It's fixed in the latest Preview releases, which you can install from this Microsoft Store link (since you seem to be on Windows 11).
The Github issue was never closed, and I never saw any release notes on it, so it may have been an upstream fix (perhaps FreeRDP), but it definitely is resolved for both me as well as the OP of that Super User question.

Printf not printing immediately, although buffering is disabled

I'm having problem with the printf function in C. It's just not printing the output, although buffering is disabled:
setbuf(stdout, NULL);
and
setvbuf(stdout, NULL, _IONBF, 0);
also I'm using fflush(stdout);, but it still doesn't work.
This is the exact code:
int setup(){
//...
printf("Setup successful\n");
fflush(stdout);
return 0;
}
int main(int argc, char *argv[]){
setbuf(stdout, NULL);
setvbuf(stdout, NULL, _IONBF, 0);
setup();
//...
)
If the info helps; I'm on Linux (raspberry Pi).
Thanks in advance!
I’ve tried reproducing your setup as closely as possible. I therefore installed Raspbian (The Raspberry Pi operating system) in a VirtualBox image and used Geany to create, compile and execute a C file. Here is the code in its entirety:
#include <stdio.h>
int main() {
printf("Setup successful\n");
}
Save this file as test.c:
Next, click on “Build” (the brick icon):
And finally, run it (click on the paper plane icon):
As you can see, this code compiles correctly, executes, and prints the message. No explicit flushing is necessary (printf to stdout automatically flushes when encountering a newline character). This behaviour is standardised and correctly implemented by the tools installed by Raspbian so it’s reliable.

Why does SDL2 have some extra delay?

SDL2 seems to have a strange behaviour that I don't think SDL1.2 had, concerning event loops. When executing a program made with the following code, there is an extra delay that makes it really slow.
#include "SDL.h"
int main(int argc, char *argv[])
{
SDL_Event event;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *wind = SDL_CreateWindow("test", 700, 100, 300, 300, 0);
while (1)
{
SDL_PollEvent(&event);
if (event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE)
break;
SDL_Delay(1000);
}
SDL_Quit();
return 0;
}
For example, when clicking on the button "escape", it takes up to 4-5 seconds before the program closes, whereas it should take less than 1 second, since the delay is fixed at 1000ms.
When using a printf in the loop, I noticed that even though the loop is working, my input is not considered before a certain amount of time.
Why is there such a delay?

Why does `ioctl(fd, EVIOCGRAB, 1)` cause key spam sometimes?

I'm trying to write my own "keyboard driver" (without actually writing a kernel module),
by grabbing the keyboard at what I assume is the lowest level of abstraction in userland: /dev/input/event*.
The following code does the grabbing, provided you change the first ocurrence of ioctl(fd, EVIOCGRAB, UNGRAB)
to ioctl(fd, EVIOCGRAB, GRAB).
// gcc main.c -o main
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <linux/input.h>
#include <fcntl.h>
#include <errno.h>
#define EXIT_KEY KEY_ESC
#define UNGRAB 0
#define GRAB 1
const char* kbd_device = "/dev/input/event4";
// ------------------------------------------------------------------------------------------------
int main(void){
int fd = open(kbd_device, O_RDONLY);
if(fd == -1){
printf("Cannot open %s. %s.\n", kbd_device, strerror(errno));
return -1;
}
if(ioctl(fd, EVIOCGRAB, UNGRAB))
printf("Couldn't grab %s. %s.\n", kbd_device, strerror(errno));
else
printf("Grabbed %s!\n", kbd_device);
while(1){
struct input_event event;
read(fd, &event, sizeof(event));
if (event.type == EV_KEY && event.value >= 0 && event.value <= 2){
printf("%d %3d\n", event.value, event.code);
if(event.code == EXIT_KEY){
ioctl(fd, EVIOCGRAB, UNGRAB);
close(fd);
return 0;
}
}
}
}
Problem
If I run gcc main.c -o main && sudo ./main, everything works as expected.
If first compile and then I run sudo ./main, however, the terminal scrolls down nonstop, as if the RETURN key was held down.
Why does happen?
Notes
I'm running Ubuntu 14.04
On my platform, /dev/input/event4 happens to be the keyboard
Motivation
I'm trying to write a keyboard "driver" that works both on X and not on X (eg. a TTY).
I understand X11's keyboard library/extension is XKB. I think the TTY's keyboard library is linux/divers/tty/vt/keyboard.c (source),
the initial keyboard map it uses is in linux/drivers/tty/vt/defkeymap.map (source), and it can be modified by using loadkeys (source here). Do correct me if I'm wrong.
When you type
gcc main.c -o main && sudo ./main ↵
GCC takes some time, so the ↵ key has been released by the time ./main runs.
When you type
sudo ./main ↵
the terminal sends the shell a newline as soon as you push down ↵, and starts executing ./main. Then the ↵ released event is seen by your program, but not by your terminal, because your program has grabbed the input device. Thus, to the terminal it looks like ↵ is stuck down, so it continues to produce newlines.
This question has been answered already, but it still lacks an elegant solution to the problem.
I had the same issue with a driver I implemented some time ago that also required capturing the keyboard.
I could not find a way to force the the kernel to recognize a key release in the device before capturing it, so the solution consists in not grabbing the device until you detect that all keys have actually been released. This can be accomplished by monitoring the device with the EVIOCGKEY ioctl AFTER opening it and BEFORE grabbing it.
OBS: Please observe that the apparently dummy read function within the while loop is necessary in order to avoid a busy wait and so that the loop will iterate after each event from the input device. Also note that the file descriptor must be configured for blocking I/O (the default).
void waitReleaseAll(int fd) {
struct input_event evt;
unsigned char key_b[KEY_MAX/8 + 1];
int i, nothing;
while ( 1 ) {
memset(key_b, 0, sizeof(key_b));
ioctl(fd, EVIOCGKEY(sizeof(key_b)), key_b);
for ( nothing = 1 , i = 0 ; i < KEY_MAX/8 + 1 ; i++ ) {
if ( key_b[i] != 0 ) { nothing = 0; break; }
}
if ( nothing ) break;
read(fd, &evt, sizeof(evt));
}
printf("All keys are now released\n");
}
To fix your problem, you should use SIGINT in your code to identify Ctrl-C keystroke from the user.
Implement SIGNAL in your code:
static volatile sig_atomic_t stop = 0;
static void interrupt_handler(int sig)
{
stop = 1;
} // Outside of the main function.
int main(int argc, char *argv[])
{
signal(SIGINT, interrupt_handler);
while (!stop) {
//your code
}
exit(0);
}

Trying to get a process running running without an SDL (percieved) crash C

Okay so I'm pretty new to programming, so I thought as my first real programming challenge I would make a chess program to teach openings. Inside my game game loop I have everything I need, except at some point in the game loop I want to stop for input from the user, and wait to process that information before drawing the screen and continuing the loop. However when I do that, if the user waits to long to input(~8 seconds)(btw the input in console input for now, that will change later) then the game just crashes and I get the standard ubuntu "do you want to force quit or wait" message. I would like to keep this message from popping up, but I don’t know how.
Here's my code btw:
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "SDL2/SDL.h"
void drawBoard(SDL_Renderer *renderer)
{}
void drawPieces(char fen[100])
{}
int processEvents(SDL_Window *window)
{}
I'm leaving these functions out because the are long and not super important(if you want me to I’ll put them up later)
void next_move(char firstmove[10], char response[10])
{
int cont = 0;
char move[6];
printf("%s\n>>", firstmove);
while(cont == 0)
{
scanf("%s", move);
if(strcmp(move, response) == 0)
cont = 1;
else
printf("Incorrect.\n%s\n>>", firstmove);
}
}
void caro_kann()
{
printf("YOU HAVE SELECTED The Caro Kann Opening ( main line )\n");
next_move("1. e4", "c6");
next_move("2. d4", "d5");
next_move("3. Nc6", "dxe4");
next_move("4. Nxe4", "Bf5");
next_move("5. Ng3", "Bg6");
next_move("6. h4", "h6");
next_move("7. Nf3", "Nd7");
printf("success\n");
}
int main()
{
int done = 0;
SDL_Event event;
SDL_Window *window;
SDL_Renderer *renderer;
//initialize everything
SDL_Init(SDL_INIT_VIDEO);
//setting up the window
window = SDL_CreateWindow("PlatoChess ALPHA 1.0",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800,
800,
0);
//Setting up the renderer
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
//setting up the program loop
while(!done)
{
if(processEvents(window) == 1)
done = 1;
caro_kann();
drawBoard(renderer);
SDL_Delay(10); //to cap the FPS
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}
Any help would be much appreciated!
First of all, "do you want to force quit or wait" is not a crash. All it means is that your program isn't processing events (which is true - you're in a blocking scanf and doing nothing). Even if you're waiting for something to happen, you still should process window events and update display if necessary, otherwise user can't close your program and if it gets overshadowed by another program (or just minimised) its display will be completely wrong.
Basically you shouldn't block in wait for input. Your options are (sorted by ascending difficulty, based entirely on my opinion):
change input scheme (e.g. use keyboard events that SDL gives you instead of stdin)
perform nonblocking read from stdin when input is available
use separate input thread (requires sync)

Resources