XI2. How to ignore events of modifier keys? - c

I'm trying to fix xneur keyboard switcher. Its author tried to add XI2 support, but broke input in the applications that use only XI2(google chrome for example).
And I'm stuck with modifiers filtering. There is the following code:
// Grab all keys...
if (has_x_input_extension) {
XIEventMask mask;
mask.deviceid = XIAllDevices;
mask.mask_len = XIMaskLen(XI_KeyPress)+
XIMaskLen(XI_KeyRelease);
mask.mask = (void *)calloc(mask.mask_len, sizeof(char));
XISetMask(mask.mask, XI_KeyPress);
XISetMask(mask.mask, XI_KeyRelease);
XISelectEvents(main_window->display, DefaultRootWindow(main_window->display), &mask, 1);
free(mask.mask);
}
else {
XGrabKey(main_window->display, AnyKey, AnyModifier, window, FALSE, GrabModeAsync, GrabModeAsync);
// ...without ModKeys.
grab_modifier_keys(window, FALSE);
}
grab_modifier_keys ungrabs key modifiers. And I don't know how to do the same with XI2(if branch).
I think it's possible to ignore those events in the event handling loop. Something like this:
int is_modifier (XEvent *event)
{
/* ??? */
}
while (1) {
XEvent event;
XNextEvent(display, &event);
if (is_modifier(event)) {
continue;
}
}
But I don't know how to implement is_modifier function.
I'd appreciate any help

Probably not a perfect solution, but here is an implementation of is_modifier I came up with:
Bool is_modifier(KeySym key_sym)
{
XModifierKeymap *modmap = XGetModifierMapping(main_window->display);
if (modmap == NULL) {
return False;
}
KeyCode key_code = XKeysymToKeycode(main_window->display, key_sym);
int size = modmap->max_keypermod * 8;
for (int i = 0; i < size; ++i) {
if (key_code == modmap->modifiermap[i]) {
return True;
}
}
XFreeModifiermap(modmap);
return False;
}

Related

My while loop is not breaking after my interrupt updates in C

I am implementing simon says as a small weekly project for school. Using arduino Uno, I'm making 10 levels each level has an extra pattern inside. example: level 1: [1], level 2: [1,2], etc... I have three buttons on my shield. the interrupts work and everything is gucci. My problem here is in this snippet
bool readInput(uint8_t pattern[], uint8_t length)
{
sei();
uint8_t current = 0;
while (current < length)
{
btnPushed = false;
while (!btnPushed)
{
#ifdef DEBUG
_delay_ms(1);
#endif
}
printf("here");
cli();
_delay_ms(200);
if (currentPushed == pattern[current])
{
printf("correct, you pushed %d\n", currentPushed);
}
else
{
printf("incorrect, lets try again\n");
return false;
}
}
btnPushed = false;
return true;
}
so basically I set my buttonPushed to false, and start listening for interrupts, once its true after clicking, I expect to exit the loop and check the input, however my interrupt is correct and I get visual feedback with a light that lights up once i push a button.
this is my ISR
ISR(PCINT1_vect)
{
uint8_t buttonCurr = currentButton();
if (buttonCurr != -1)
{
if (!btn1Pushed && buttonCurr == 0)
{
btn1Pushed = true;
}
currentPushed = buttonCurr;
blinkLed(currentPushed, 1);
btnPushed = true;
}
}
my current button returns 0-2 for buttons that are clicked, and -1 if nothing was clicked.
this is the rest of my code, which is working pretty much
int currentPushed = -1;
bool won;
bool btnPushed = false;
bool btn1Pushed = false;
ISR(PCINT1_vect)
{
uint8_t buttonCurr = currentButton();
if (buttonCurr != -1)
{
if (!btn1Pushed && buttonCurr == 0)
{
btn1Pushed = true;
}
currentPushed = buttonCurr;
blinkLed(currentPushed, 1);
btnPushed = true;
}
}
int main(void)
{
enableAllButtons();
enableAllLeds();
lightDownAllLeds();
prepareButtonsForInterrupt();
initUSART();
init();
play();
if (won)
{
printf("Simon says you win");
}
else
{
printf("simon says do better");
}
return 0;
}
void init(void)
{
printf("LETS PLAY SIMON SAYS\nPress button 1 to start!\n");
int seed = 0;
while (!btn1Pushed)
{
blinkLed(3, 4);
seed++;
}
srand(seed);
printf("Get ready!\n");
btnPushed = false;
cli();
}
void createRandomPattern(uint8_t array[], uint8_t length)
{
for (int i = 0; i < length; i++)
{
array[i] = rand() % 3;
}
}
void play(uint8_t pattern[])
{
uint8_t fullPattern[MAX_PATTERN_LENGTH];
createRandomPattern(fullPattern, MAX_PATTERN_LENGTH);
for (int i = 1; i <= MAX_PATTERN_LENGTH; i++)
{
printf("========LEVEL %d===========\n", i);
playPuzzle(fullPattern, i);
#ifdef DEBUG
printPuzzle(fullPattern, i);
#endif
readInput(fullPattern, i) ?: i--;
}
}
bool readInput(uint8_t pattern[], uint8_t length)
{
sei();
uint8_t current = 0;
while (current < length)
{
btnPushed = false;
while (!btnPushed)
{
}
cli();
if (currentPushed == pattern[current])
{
printf("correct, you pushed %d\n", currentPushed);
}
else
{
printf("incorrect, lets try again\n");
return false;
}
current++;
}
btnPushed = false;
return true;
}
void printPuzzle(uint8_t pattern[], uint8_t length)
{
printf("[ ");
for (int i = 0; i < length; i++)
{
printf("%d ", pattern[i]);
}
printf("]\n");
}
void playPuzzle(uint8_t pattern[], uint8_t length)
{
for (int i = 0; i < length; i++)
{
lightUpOneLed(pattern[i]);
_delay_ms(500);
lightDownOneLed(pattern[i]);
}
}
btnPushed is defined as bool btnPushed = false;.
So when you write:
while (!btnPushed)
{
#ifdef DEBUG
_delay_ms(1);
#endif
}
Nothing in the loop will change btnPushed so there is no point for the compiler to ever check btnPushed again. So what the compiler sees is this:
if (!btnPushed)
while(true)
{
#ifdef DEBUG
_delay_ms(1);
#endif
}
You have to tell the compiler that the value of btnPushed will change unexpectantly when the interrupt fires by using:
volatile bool btnPushed = false;

How to count 'on event' in CANoe Capl?

I'd like to count on event for 200ms.
I tried with this code in CANoe Capl but it's not working well.
I don't know what the problem is.
help me plz.
MainActivity.Capl
variables
{
int timerConditionChecker = 0;
int lockStatusMonitor = 0;
mstimer conutCheckTimer;
}
on timer conutCheckTimer
{
//do nothing
}
on sysvar_update sysvar::Frame2
{
if(timerConditionChecker == 0)
{
lockStatusMonitor++;
timerConditionChecker = 1;
setTimer(conutCheckTimer, 500);
}
else if(timerConditionChecker == 1)
{
if(timeToElapse(conutCheckTimer) > 200)
{
timerConditionChecker = 2;
}
else
{
lockStatusMonitor++;
}
}
else if(timerConditionChecker == 2)
{
timerConditionChecker = 3;
Write("lockStatusMonitorCount = %d",lockStatusMonitor);
}
else{}
}
What about this (I mostly used your variable names):
variables
{
int lockStatusMonitor = 0;
mstimer conutCheckTimer;
}
on timer conutCheckTimer
{
// Is called after 200ms and will output how often the sysvar was updated within these 200ms
Write("lockStatusMonitorCount = %d",lockStatusMonitor);
}
on sysvar_update sysvar::Frame2
{
if(isTimerActive(conutCheckTimer))
{
// In case the 200ms have already started, just count
lockStatusMonitor++;
}
else {
// Timer is not yet active, so start counting for the next 200ms now
lockStatusMonitor = 0; // or = 1 depending on whether your use case
setTimer(conutCheckTimer, 200);
}
}
Apart from that, using the CAPL debugger should help you to solve these kind of problems.

Invalid renderer SDL2

I am looking through the code and i cant find solution for the problem of invalid renderer. I am beginner with SDL2 and i have to write code in pure C.
I think that in my code there is more errors but because of this one i cant go further. Code is half in polish language so if u cant get what is where i can rewrite this a bit . Problem occure when in main i try to load function"Odczyt_z_Pliku". Probably somewhere there is a problem.
SDL_GetError() says" invalid renderer.
#include<SDL.h>
#include<stdio.h>
#include<SDL_image.h>
#pragma warning(disable : 4996)
#define WYSOKOSC_EKRANU 768
#define SZEROKOSC_EKRANU 1024
typedef enum bool{
false,true
}bool;
typedef struct sTekstura {
int wysokosc;
int szerokosc;
SDL_Texture *Tekstura;
}sTekstura;
void IniTekstury(sTekstura T)
{
T.wysokosc = 0;
T.szerokosc = 0;
T.Tekstura = NULL;
}
void free(sTekstura T)
{
//Free texture if it exists
if (T.Tekstura != NULL)
{
SDL_DestroyTexture(T.Tekstura);
T.Tekstura = NULL;
T.szerokosc = 0;
T.wysokosc = 0;
}
}
int Odczyt_z_Pliku(char nazwa[50],sTekstura T,SDL_Renderer* Renderer)
{
free(T);
SDL_Texture* nTekstura = NULL;
//Load image at specified path
SDL_Surface* Powierzchnia = IMG_Load(nazwa);
if (Powierzchnia == NULL)
{
printf("Unable to load image %s! SDL_image Error: %s\n", nazwa, IMG_GetError());
}
else
{
SDL_SetColorKey(Powierzchnia, SDL_TRUE, SDL_MapRGB(Powierzchnia->format, 0xFF, 0xFF, 0xFF));
//Create texture from surface pixels
nTekstura = SDL_CreateTextureFromSurface(Renderer, Powierzchnia);
if (nTekstura == NULL)
{
printf("Unable to create texture from %s! SDL Error: %s\n", nazwa, SDL_GetError());
}
else
{
//Get image dimensions
T.szerokosc = Powierzchnia->w;
T.wysokosc = Powierzchnia->h;
}
//Get rid of old loaded surface
SDL_FreeSurface(Powierzchnia);
}
//Return success
T.Tekstura = nTekstura;
if (T.Tekstura != NULL)
{
return 1;
}
else
{
return 0;
}
}
bool Inicjalizacja(SDL_Window *Okno,SDL_Renderer *Renderer)
{
//Initialization flag
bool success = true;
//Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Set texture filtering to linear
if (!SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1"))
{
printf("Warning: Linear texture filtering not enabled!");
}
//Create window
Okno = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SZEROKOSC_EKRANU, WYSOKOSC_EKRANU, SDL_WINDOW_SHOWN);
if (Okno == NULL)
{
printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Create renderer for window
Renderer = SDL_CreateRenderer(Okno, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (Renderer == NULL)
{
printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
}
else
{
//Initialize renderer color
SDL_SetRenderDrawColor(Renderer, 0xFF, 0xFF, 0xFF, 0xFF);
//Initialize PNG loading
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & imgFlags))
{
printf("SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError());
success = false;
}
}
}
}
return success;
}
void setBlendMode(sTekstura T, SDL_BlendMode blending) //MK: Funkcja ustawiająca przezroczystosc
{
//Set blending function
SDL_SetTextureBlendMode(T.Tekstura, blending);
}
void setAlpha(sTekstura T,Uint8 alpha) //MK: Funkcja ustawiająca przezroczystość
{
//Modulate texture alpha
SDL_SetTextureAlphaMod(T.Tekstura, alpha);
}
void render(int x, int y,sTekstura T,SDL_Renderer *Renderer)
{
//Set rendering space and render to screen
SDL_Rect renderQuad = { x, y, T.szerokosc, T.wysokosc };
SDL_RenderCopy(Renderer, T.Tekstura, NULL, &renderQuad);
}
int main(int argc, char *argv[])
{
SDL_Window * Okno = NULL;
SDL_Renderer* Renderer = NULL;
sTekstura TloMenu;
TloMenu.szerokosc = 0;
TloMenu.wysokosc = 0;
TloMenu.Tekstura = NULL;
sTekstura TloGra;
TloGra.szerokosc = 0;
TloGra.wysokosc = 0;
TloGra.Tekstura = NULL;
sTekstura Pudlo;
Pudlo.szerokosc = 0;
Pudlo.wysokosc = 0;
Pudlo.Tekstura = NULL;
sTekstura Sciana;
Sciana.szerokosc = 0;
Sciana.wysokosc = 0;
Sciana.Tekstura = NULL;
sTekstura StartGry;
StartGry.szerokosc = 0;
StartGry.wysokosc = 0;
StartGry.Tekstura = NULL;
sTekstura KoniecGry;
KoniecGry.szerokosc = 0;
KoniecGry.wysokosc = 0;
KoniecGry.Tekstura = NULL;
SDL_Event e;
//Start up SDL and create window
if (!Inicjalizacja(Okno,Renderer))
{
printf("Failed to initialize!\n");
}
else
{
if(!Odczyt_z_Pliku("MENU BOMBERMAN.png", Sciana, Renderer))
{
puts("Nie wczytano kostki");
return 0;
}
if (!Odczyt_z_Pliku("pudlo3.bmp", Pudlo, Renderer))
{
puts("Nie wczytano pudla");
return 0;
}
if (!Odczyt_z_Pliku("MenuBomberman.bmp", TloMenu, Renderer))
{
puts("Nie wczytano menu");
return 0;
}
if (!Odczyt_z_Pliku("Mapa.bmp", TloGra, Renderer))
{
puts("Nie wczytano mapy");
return 0;
}
if (!Odczyt_z_Pliku("NEW GAME.bmp", StartGry, Renderer))
{
puts("Nie wczytano napisu nowej gry");
return 0;
}
else
{
//Set standard alpha blending
setBlendMode(StartGry, SDL_BLENDMODE_BLEND);
}
if (!Odczyt_z_Pliku("exitgimp.bmp", KoniecGry, Renderer))
{
puts("Nie wczytano napisu koniec gry");
return 0;
}
else
{
//Set standard alpha blending
setBlendMode(StartGry, SDL_BLENDMODE_BLEND);
}
//Main loop flag
bool quit = false;
//Modulation component
Uint8 AlphaStartu = 255;
Uint8 AlphaKonca = 127;
//While application is running
while (!quit)
{
//Handle events on queue
while (SDL_PollEvent(&e) != 0)
{
//User requests quit
if (e.type == SDL_QUIT)
{
quit = true;
}
//Handle key presses
else if (e.type == SDL_KEYDOWN)
{
//Increase alpha on w
if (e.key.keysym.sym == SDLK_w)
{
AlphaKonca = 127;
AlphaStartu = 255;
}
//Decrease alpha on s
else if (e.key.keysym.sym == SDLK_s)
{
AlphaKonca = 256;
AlphaStartu = 127;
}
}
}
//Clear screen
SDL_SetRenderDrawColor(Renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(Renderer);
//Render background
render(0, 0, TloMenu, Renderer);
//Render front blended
setAlpha(KoniecGry,AlphaKonca);
setAlpha(StartGry, AlphaStartu);
render(0, 0,StartGry,Renderer);
render(0, 0,KoniecGry,Renderer);
//Update screen
SDL_RenderPresent(Renderer);
}
}
//Free resources and close SDL
close();
return 0;
}
When you get to Odczyt_z_Pliku, Renderer is still a NULL pointer.
As it stands, in your main() function you have a variable Renderer of type SDL_Renderer* (initialized to NULL). You then pass that value NULL into SDL_Renderer* which also takes an argument of type SDL_Renderer*.
However, in C this is just a pass by copy of the value of the pointer itself (not the value pointed to by the pointer). In other words, the argument Renderer to your function just creates a local variable in that function. So in Odczyt_z_Pliku when you do Renderer = SDL_CreateRenderer(...); that may return a new pointer but it's only assigning it to the local variable Renderer, but this has no effect on the Renderer variable in your main() function.
In C, the way to write a function that sets the value of a pointer that is a local variable in the calling function is to use a double pointer. That is, change the signature of Inicjalizacja to
bool Inicjalizacja(SDL_Window **Okno, SDL_Renderer **Renderer)
then in main() (or wherever else) call it like:
SDL_Window * Okno = NULL;
SDL_Renderer* Renderer = NULL;
...
if (!Inicjalizacja(&Okno, &Renderer)) {
...
}
and so on. (Note: You made the same mistake with the SDL_Window Okno as well, and possibly elsewhere--I haven't read the full code).
The syntax &Okno means pass the address of (i.e. a pointer to) the variable Okno. Since Okno is itself a pointer, the address of the pointer is a double pointer.
Then in Inicjalizacja write:
*Renderer = SDL_CreateRenderer(...);
and similarly with Okno. The *Renderer syntax (which I find somewhat confusing) means the value pointed to by a pointer. Since Renderer here is a double pointer, this means assign the single pointer (of type Renderer*) into the pointer pointed to by Renderer. Now the Renderer* pointer in your main() function will be properly initialized.
Note, similarly you should change the following check to:
if (*Renderer == NULL) {...}
and so on. We know Renderer != NULL since it's a pointer to a local variable allocated in our main() function. The interesting question is what value SDL_CreateRenderer returned, so we want to look at *Renderer.

With SFML 1.6, what is the best way to count button presses?

For Example:
int count;
//Code to count key presses here
sf::String String("You have pressed a key this many times: " + count );
I already know how to convert the int to a string and insert it.
Use events:
#include <SFML/Graphics.hpp>
int main()
{
// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "SFML window");
int count = 0;
while (window.IsOpened())
{
sf::Event event;
while (window.GetEvent(event))
{
if (event.Type == sf::Event::Closed)
window.Close();
if (event.Type == sf::Event::KeyPressed && event.Key.Code == sf::Key::A)
++count;
}
window.Clear();
// Do whatever you want with count.
window.Display();
}
return 0;
}

Allegro 5 game: game loop that runs at constant speed?

What is the best way to code a game loop in Allegro 5 that always runs at the same speed, and that properly separates drawing logic from update logic? Should I use threads or not? Should I make use of the new Allegro event system?
Taken from the allegro wiki:
al_install_timer(1.0 / FPS);
...
while (1) {
al_wait_for_event(queue, &event);
/* handle input events */
if (event.type == ALLEGRO_EVENT_TIMER) {
handle_game_tick();
need_redraw = true;
}
if (need_redraw && al_event_queue_is_empty(queue)) {
render_last_frame();
need_redraw = false;
}
}
If you want frame skipping, skip the render_last_frame() command whenever you detect that you are lagging behind in frames (e.g. by using the al_current_time() function).
Here is a more complete version of Allefant's answer (follow the link for detailed line-by-line explanation):
#include <stdio.h>
#include <allegro5/allegro.h>
const float FPS = 60;
int main(int argc, char **argv)
{
ALLEGRO_DISPLAY *display = NULL;
ALLEGRO_EVENT_QUEUE *event_queue = NULL;
ALLEGRO_TIMER *timer = NULL;
bool redraw = true;
if(!al_init()) {
fprintf(stderr, "failed to initialize allegro!\n");
return -1;
}
timer = al_create_timer(1.0 / FPS);
if(!timer) {
fprintf(stderr, "failed to create timer!\n");
return -1;
}
display = al_create_display(640, 480);
if(!display) {
fprintf(stderr, "failed to create display!\n");
al_destroy_timer(timer);
return -1;
}
event_queue = al_create_event_queue();
if(!event_queue) {
fprintf(stderr, "failed to create event_queue!\n");
al_destroy_display(display);
al_destroy_timer(timer);
return -1;
}
al_register_event_source(event_queue, al_get_display_event_source(display));
al_register_event_source(event_queue, al_get_timer_event_source(timer));
al_clear_to_color(al_map_rgb(0,0,0));
al_flip_display();
al_start_timer(timer);
while(1)
{
ALLEGRO_EVENT ev;
al_wait_for_event(event_queue, &ev);
if(ev.type == ALLEGRO_EVENT_TIMER) {
redraw = true;
}
else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
break;
}
if(redraw && al_event_queue_is_empty(event_queue)) {
redraw = false;
al_clear_to_color(al_map_rgb(0,0,0));
al_flip_display();
}
}
al_destroy_timer(timer);
al_destroy_display(display);
al_destroy_event_queue(event_queue);
return 0;
}

Resources