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_RegisterEvents.
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_SetEventFilter a SDL_GetEventFilter. 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_DelEventWatch.
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ínkamiStaženo 639x (11.77 MB)