Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 13 - SDL - Vlastní události a filtrování

V předchozí lekci, SDL - Obecná práce s událostmi, jsme se zabývali manipulací s frontou událostí

V aplikaci často potřebujeme vlastní události. Může se jednat o základní věci, jako vznik kolize, spuštění určitého zvuku a dále. Všechny tyto věci lze (ale není nutné) řešit přes události. Proto si dnes ukážeme, jak můžeme vytvořit vlastní událost a vložit ji do fronty.

Vytvoření vlastních událostí

K vytvoření vlastní události budeme potřebovat vlastní typ. type je Uint32, to znamená, že může nabývat celkem 0xFFFF = 65535 hodnot. Konstanta SDL_USEREVENT, od které by měly typy vlastních událostí začínat, má hodnotu 0x8000 = 32768. Sami tedy můžeme vytvořit celkem 32767 událostí – máme dostatek prostoru pro vlastní události. Tím bych naši matematickou vložku ukončil a podíváme se na praktickou část.

Nejjednodušší je si pro každou událost vytvořit konstantu v hlavičkovém souboru. Později nebudeme muset řešit kolize, až se počet událostí zvětší nad únosnou míru. Druhou možností je typy událostí generovat za běhu programu pomocí funkce SDL_RegisterE­vents. Jestliže už nebudou k dispozici další volné události, program vrátí (Uint32)-1. Osobně se přikláním ke konstantám v hlavičkových souborech. Bohužel nejsou oba postupy navzájem kompatibilní.

Pro uživatelské události máme k dispozici SDL_UserEvent, ke kterému přistupuje skrz user atribut. Struktura má dva ukazatele typu void, to znamená, že můžeme přenést prakticky libovolná data, respektive ukazatele na ně. Nakonec musíme událost vložit do fronty funkcí SDL_PushEvent nebo SDL_PeepEvents.

Filtrování událostí

Všechny filtrovací funkce pracují s interní frontou - probíhá během volání SDL_PumpEvents. Jak už bylo poznamenáno na začátku, v aplikaci se nedozvíme o tom, že uživatel právě teď něco provádí. Vždy se dozvíme jen to, že něco provedl. Okamžitá zpětná vazba není možná. To je důvod, proč filtrování probíhá až během přenášení událostí z externí fronty do interní.

První možnost je zablokovat všechny události určitého typu. Použijeme k tomu funkci SDL_EventState. V prvním parametru předáme typ události, kterou nechceme v aplikaci získávat. Druhým parametrem je jedna z hodnot SDL_QUERY pro dotázání na aktuální stav, SDL_IGNORE pro ignorování události a SDL_ENABLE pro opětovné získávání události.

Další v řadě jsou funkce SDL_SetEventFil­ter a SDL_GetEventFil­ter. Níže uvádím definice každé funkce.

int YourEventFilter(void* userdata, SDL_Event* event);
void SDL_SetEventFilter(SDL_EventFilter filter, void* userdata);
SDL_bool SDL_GetEventFilter(SDL_EventFilter* filter, void**  userdata);

Při nastavení filtru můžeme druhým parametrem předat libovolný objekt, který dostane filtrovací funkce při jejím zavolání. Jestliže filtrovací funkce vrátí hodnotu 0, událost nebude do interní fronty přidána. Naopak při hodnotě 1 přidána bude. Funkce by měla být skutečně použita pro filtrování. Pokud nás bude zajímat pouze vnitřní stav události, použijeme Event Watch.

Event Watch přidáme funkcí SDL_AddEventWatch a smažeme funkcí SDL_DelEventWat­ch.

int YourEventFilter(void* userdata, SDL_Event* event);
void SDL_AddEventWatch(SDL_EventFilter filter, void* userdata);
void SDL_DelEventWatch(SDL_EventFilter filter, void* userdata);

Vidíme, že callback je stejný jako pro filtr. Na rozdíl od něj, návratová hodnota callbacku je ignorována a jak je podle pojmenování funkcí patrné, callbacků může být několik. Můžeme mít samostatný callback pro každý typ události, ale bude potřeba na začátku každého callbacku ověřit, zda jde o správný typ. Není možné nikde nastavit, pro který typ události je callback určen - je volán pro všechny typy.

Použití filtru a Event Watch není tak snadné, jak by se na první pohled mohlo zdát. Oba callbacky mohou běžet v samostatném vlákně. Problematika vícevláknových aplikací je mimo rozsah tohoto tutoriálu. Zde platí pouze jednoduché pravidlo – data předaná při vytváření callbacku by se neměla v žádné části aplikace měnit. Poté bude vše fungovat, jak má. Callbacky se volají i pro události vložené do fronty funkcí SDL_PushEvent, ale už ne pro funkci SDL_PeepEvents. Při návrhu programu je s tím potřeba počítat.

Poslední funkcí je SDL_FilterEvents. V tomto případě proběhne předaný callback pro každou událost v interní frontě. Jedná se o jednorázovou záležitost na aktuální interní frontě.

Funkce jsou seřazeny tak, jak probíhají za sebou. Jestliže funkce zmíněná výše odfiltruje událost, funkce nebo callback zmíněný pod ní již neproběhne. Nastavíme-li SDL_KEYDOWN state na SDL_IGNORE, Event Watch se nezavolá. Pro přehlednost uvádím graf (první proběhne funkce vlevo).

SDL_EventState -> SDL_ SetEventFilter -> SDL_AddEventWatch -> SDL_FilterEvents

Příklad

Přiložený program obsahuje i prvky z minulé lekce a demonstruje vytvoření vlastní události, filtrování a smazání události po SDL_WarpMouseInWindow.

V příští lekci, SDL - RWops, vlákna a další, se podíváme na abstrakci souborů nebo vícevláknové programování.


 

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 606x (11.77 MB)

 

Předchozí článek
SDL - Obecná práce s událostmi
Všechny články v sekci
SDL
Přeskočit článek
(nedoporučujeme)
SDL - RWops, vlákna a další
Článek pro vás napsal Patrik Valkovič
Avatar
Uživatelské hodnocení:
Ještě nikdo nehodnotil, buď první!
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu (NodeJS).
Aktivity