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.
Related
I am trying to learn the PDcurses package in C but i keep getting this problem:
LINES value must be >= 2 and <= 1252: got -1
initscr(): Unable to create SP
My code:
#include <curses.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *lsofFile_p = popen("hostname", "r");
if (!lsofFile_p)
{
return -1;
}
int row,col;
char buffer[1024];
char *line_p = fgets(buffer, sizeof(buffer), lsofFile_p);
pclose(lsofFile_p);
initscr(); /* start the curses mode */
start_color();
init_pair(1,COLOR_GREEN,COLOR_BLACK);
init_pair(2,COLOR_BLUE,COLOR_BLACK);
getmaxyx(stdscr,row,col); /* get the number of rows and columns */
attron(COLOR_PAIR(1));
mvprintw(row/2,(col-strlen(line_p)-26)/2,"Your computer name is : ");
attroff(COLOR_PAIR(1));
attron(COLOR_PAIR(2)|A_BOLD);
printw("%s",line_p);
/* print the message at the center of the screen */
attroff(COLOR_PAIR(2)|A_BOLD);
wrefresh(stdscr);
system("pause");
endwin();
}
This works fine in Linux with ncurses instead of curses. If i simply try printing Hello world, it works too. So I have no idea where it is going wrong or how to fix it.
I am using MinGW gcc for compiling and I've got PDCurses installed from there too. I am running the code on Windows Terminal.
The error message indicates that PDcurses was unable to get the screen size from the Windows console. This may mean that it failed to figure out what type of terminal you are using (Windows console? Something else?). You may be able to get past this by setting the LINES environment variable to the correct value for your screen.
PDCurses tries to get this info by calling the windows function GetConsoleScreenBufferInfoEx in kernel32.dll, which should be pretty independent of what you're using compiler/terminal/whatnot, as long as you do have some kind of terminal window (not running headless)
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)
What I am trying to do
So, I have been trying to access keyboard input in Linux. Specifically, I need to be able to access modifier key presses without other keys being pressed. Furthermore, I want to be able to do this without an X system running.
So, in short, my requirements are these:
Works on Linux
Does not need X11
Can retrieve modifier key press without any other keys being pressed
This includes the following keys:
Shift
Control
Alt
All I need is a simple 0 = not pressed, 1 = currently pressed to let me know if
the key is being held down when the keyboard is checked
My computer setup
My normal Linux machine is on a truck towards my new apartment; so, I only have a Macbook Air to work with right now. Therefore, I am running Linux in a VM to test this out.
Virtual Machine in VirtualBox
OS: Linux Mint 16
Desktop Environment: XFCE
Everything below was done in this environment. I've tried both with X running and in one of the other ttys.
My Thoughts
I'll alter this if someone can correct me.
I've done a fair bit of reading to realize that higher-level libraries do not provide this kind of functionality. Modifier keys are used with other keys to provide an alternate key code. Accessing the modifier keys themselves through a high-level library in Linux isn't as easy. Or, rather, I haven't found a high-level API for this on Linux.
I thought libtermkey would be the answer, but it doesn't seem to support the Shift modifier key any better than normal keystroke retrieval. I'm also not sure if it works without X.
While working with libtermkey (before I realized it didn't get shift in cases like Shift-Return), I was planning to write a daemon that would run to gather keyboard events. Running copies of the daemon program would simply pipe requests for keyboard data and receive keyboard data in response. I could use this setup to have something always running in the background, in case I cannot check key code statuses at specific times (have to be receive key codes as they happen).
Below are my two attempts to write a program that can read from the Linux keyboard device. I've also included my small check to make sure I had the right device.
Attempt #1
I have tried to access the keyboard device directly, but am encountering issues. I have tried the suggestion here that is in another Stack Overflow thread. It gave me a segmentation fault; so, I changed it from fopen to open:
// ...
int fd;
fd = open("/dev/input/by-path/platform-i8042-serio-0-event-kbd", O_RDONLY);
char key_map[KEY_MAX/8 + 1];
memset(key_map, 0, sizeof(key_map));
ioctl(fd, EVIOCGKEY(sizeof key_map), key_map);
// ...
While there was no segmentation fault, there was no indicator of any key press (not just modifier keys). I tested this using:
./foo && echo "TRUE" || echo "FALSE"
I've used that to test for successful return codes from commands quite a lot; so, I know that's fine. I've also outputted the key (always 0) and mask (0100) to check. It just doesn't seem to detect anything.
Attempt #2
From here, I thought I'd try a slightly different approach. I wanted to figure out what I was doing wrong. Following this page providing a snippet demonstrating printing out key codes, I bundled that into a program:
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <linux/input.h>
int main(int argc, char** argv) {
uint8_t keys[128];
int fd;
fd = open("/dev/input/by-path/platform-i8042-serio-event-kbd", O_RDONLY);
for (;;) {
memset(keys, 0, 128);
ioctl (fd, EVIOCGKEY(sizeof keys), keys);
int i, j;
for (i = 0; i < sizeof keys; i++)
for (j = 0; j < 8; j++)
if (keys[i] & (1 << j))
printf ("key code %d\n", (i*8) + j);
}
return 0;
}
Previously, I had the size to 16 bytes instead of 128 bytes. I should honestly spend a bit more time understanding ioctl and EVIOCGKEY. I just know that it supposedly maps bits to specific keys to indicate presses, or something like that (correct me if I'm wrong, please!).
I also didn't have a loop initially and would just hold down various keys to see if a key code appeared. I received nothing; so, I thought a loop might make the check easier to test in case a missed something.
How I know the input device is the right one
I tested it by running cat on the input device. Specifically:
$ sudo cat /dev/input/by-path/platform-i8042-serio-0-event-kbd
Garbage ASCII was sent to my terminal on key press and release events starting with the return (enter) key when I began the output using cat. I also know that this seems to work fine with modifier keys like shift, control, function, and even Apple's command key on my Macbook running a Linux VM. Output appeared when a key was pressed, began to appear rapidly from subsequent signals sent by holding the key down, and outputted more data when a key was released.
So, while my approach may not be the right one (I'm willing to hear any alternative), the device seems to provide what I need.
Furthermore, I know that this device is just a link pointing to /dev/input/event2 from running:
$ ls -l /dev/input/by-path/platform-i8042-serio-0-event-kbd
I've tried both programs above with /dev/input/event2 and received no data. Running cat on /dev/input/event2 provided the same output as with the link.
Open the input device,
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <stdio.h>
static const char *const evval[3] = {
"RELEASED",
"PRESSED ",
"REPEATED"
};
int main(void)
{
const char *dev = "/dev/input/by-path/platform-i8042-serio-0-event-kbd";
struct input_event ev;
ssize_t n;
int fd;
fd = open(dev, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Cannot open %s: %s.\n", dev, strerror(errno));
return EXIT_FAILURE;
}
and then read keyboard events from the device:
while (1) {
n = read(fd, &ev, sizeof ev);
if (n == (ssize_t)-1) {
if (errno == EINTR)
continue;
else
break;
} else
if (n != sizeof ev) {
errno = EIO;
break;
}
The above snippet breaks out from the loop if any error occurs, or if the userspace receives only a partial event structure (which should not happen, but might in some future/buggy kernels). You might wish to use a more robust read loop; I personally would be satisfied by replacing the last break with continue, so that partial event structures are ignored.
You can then examine the ev event structure to see what occurred, and finish the program:
if (ev.type == EV_KEY && ev.value >= 0 && ev.value <= 2)
printf("%s 0x%04x (%d)\n", evval[ev.value], (int)ev.code, (int)ev.code);
}
fflush(stdout);
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
For a keypress,
ev.time: time of the event (struct timeval type)
ev.type: EV_KEY
ev.code: KEY_*, key identifier; see complete list in /usr/include/linux/input.h
ev.value: 0 if key release, 1 if key press, 2 if autorepeat keypress
See Documentation/input/input.txt in the Linux kernel sources for further details.
The named constants in /usr/include/linux/input.h are quite stable, because it is a kernel-userspace interface, and the kernel developers try very hard to maintain compatibility. (That is, you can expect there to be new codes every now and then, but existing codes rarely change.)
I have recently been introduced to ncurses for asynchronous keyboard key listening, and getting on well with it. One issue i'm facing is that you can only have text on the visible screen, no scrollbars. I was wondering if its possible to keep using ncurses as it is so lovely, but have the program still keep the scrollbars rather than getting to the last line and staying there.
scroll(). You have to set scrollok(win, TRUE) first. Actually if you just want to spew data like a normal terminal you only need to set scrollok() by itself.
#include <ncurses.h>
int main(void)
{
int i = 0;
initscr();
scrollok(stdscr,TRUE);
while(1)
{
printw("%d - lots and lots of lines flowing down the terminal\n", i);
++i;
refresh();
}
endwin();
return 0;
}
I am searching for a way to automatically take a screenshot of my X server if a window is created or the contents of a windows have changed.
I am currently achieving this by listening to X11 events, but not all changes are reported.
Look at XDamageNotifyEvent, XDamageQueryExtension, XDamageCreate, XDamageSubtract from the Damage extension. This extension is used to track changing window contents.
http://www.freedesktop.org/wiki/Software/XDamage
A good source of sample code would be anything that makes thumbnails of windows. Also, any compositing window manager (Compiz, some flavors of metacity, etc.) would contain damage-tracking code.
Without the extension, you basically have to poll (update window contents in a timeout).
I know this post is quite dead. And yet, the documentation of X11 is terrible, and it took me a long time to get XDamage working in any regard. So here is an example that will print a line to the console every time the root X11 window changes, based on the documentation mentioned in Havoc's post, and loosely based on this link:
#include <stdio.h>
#include <stdlib.h>
#include <X11/extensions/Xdamage.h>
#include <X11/Xlib.h>
#include <signal.h>
int endnow = 0;
void cleanup(int SIGNUM){
endnow = 1;
}
int main(){
Display *display;
display = XOpenDisplay(":0");
if(!display){
perror("could not open display");
exit(1);
}
Window root = DefaultRootWindow(display);
int damage_event, damage_error, test;
//this line is necessary to initialize things
test = XDamageQueryExtension(display, &damage_event, &damage_error);
/*The "event" output is apparently the integer that appears in the
Xevent.type field when XNextEvent returns an XDamage event */
printf("test = %d, event = %d, error = %d\n",test,damage_event, damage_error);
//This is the handler for the XDamage interface
//See the XDamage documentation for more damage report levels
// http://www.freedesktop.org/wiki/Software/XDamage
Damage damage = XDamageCreate(display, root, XDamageReportNonEmpty);
signal(SIGINT,cleanup);
// XCloseDisplay(display);
while(endnow == 0){
XEvent event;
XNextEvent(display,&event);
printf("event.type = %d\n",event.type);
//this line resets the XDamage handler
XDamageSubtract(display,damage,None,None);
}
XCloseDisplay(display);
printf("done\n");
exit(0);
}
Naturally, if you run this from a console on the same screen as your display :0, every line it prints it will activate itself, and be kinda unstable. But it is a good demonstration if you run it from an ssh terminal on another computer.